Build fix: missing type traits on gcc < 5.0
[lttng-tools.git] / src / common / macros.hpp
1 /*
2 * Copyright (C) 2011 EfficiOS Inc.
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 */
8
9 #ifndef _MACROS_H
10 #define _MACROS_H
11
12 #include <common/compat/string.hpp>
13
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include <type_traits>
19
20 /*
21 * Takes a pointer x and transform it so we can use it to access members
22 * without a function call. Here an example:
23 *
24 * #define GET_SIZE(x) LTTNG_REF(x)->size
25 *
26 * struct { int size; } s;
27 *
28 * printf("size : %d\n", GET_SIZE(&s));
29 *
30 * For this example we can't use something like this for compatibility purpose
31 * since this will fail:
32 *
33 * #define GET_SIZE(x) x->size;
34 *
35 * This is mostly use for the compatibility layer of lttng-tools. See
36 * poll/epoll for a good example. Since x can be on the stack or allocated
37 * memory using malloc(), we must use generic accessors for compat in order to
38 * *not* use a function to access members and not the variable name.
39 */
40 #define LTTNG_REF(x) ((typeof(*x) *)(x))
41
42 #ifdef NDEBUG
43 /*
44 * Force usage of the assertion condition to prevent unused variable warnings
45 * when `assert()` are disabled by the `NDEBUG` definition.
46 */
47 # define LTTNG_ASSERT(_cond) ((void) sizeof((void) (_cond), 0))
48 #else
49 # include <assert.h>
50 # define LTTNG_ASSERT(_cond) assert(_cond)
51 #endif
52
53 /*
54 * Memory allocation zeroed
55 */
56
57 static inline
58 void *zmalloc_internal(size_t size)
59 {
60 return calloc(1, size);
61 }
62
63 template <typename T>
64 struct can_malloc
65 {
66 /*
67 * gcc versions before 5.0 lack some type traits defined in C++11.
68 * Since in this instance we use the trait to prevent misuses
69 * of malloc (and statically assert) and not to generate different
70 * code based on this property, simply set value to true and allow
71 * the code to compile. Anyone using a contemporary compiler will
72 * catch the error.
73 */
74 #if __GNUG__ && __GNUC__ < 5
75 static constexpr bool value = true;
76 #else
77 static constexpr bool value = std::is_trivially_constructible<T>::value;
78 #endif
79 };
80
81 /*
82 * Malloc and zero-initialize an object of type T, asserting that T can be
83 * safely malloc-ed (is trivially constructible).
84 */
85 template<typename T>
86 T *zmalloc()
87 {
88 static_assert (can_malloc<T>::value, "type can be malloc'ed");
89 return (T *) zmalloc_internal(sizeof(T));
90 }
91
92 /*
93 * Malloc and zero-initialize a buffer of size `size`, asserting that type T
94 * can be safely malloc-ed (is trivially constructible).
95 */
96 template<typename T>
97 T *zmalloc(size_t size)
98 {
99 static_assert (can_malloc<T>::value, "type can be malloc'ed");
100 LTTNG_ASSERT(size >= sizeof(T));
101 return (T *) zmalloc_internal(size);
102 }
103
104 /*
105 * Malloc and zero-initialize an array of `nmemb` elements of type T,
106 * asserting that T can be safely malloc-ed (is trivially constructible).
107 */
108 template<typename T>
109 T *calloc(size_t nmemb)
110 {
111 static_assert (can_malloc<T>::value, "type can be malloc'ed");
112 return (T *) zmalloc_internal(nmemb * sizeof(T));
113 }
114
115 /*
116 * Malloc an object of type T, asserting that T can be safely malloc-ed (is
117 * trivially constructible).
118 */
119 template<typename T>
120 T *malloc()
121 {
122 static_assert (can_malloc<T>::value, "type can be malloc'ed");
123 return (T *) malloc(sizeof(T));
124 }
125
126 /*
127 * Malloc a buffer of size `size`, asserting that type T can be safely
128 * malloc-ed (is trivially constructible).
129 */
130 template<typename T>
131 T *malloc(size_t size)
132 {
133 static_assert (can_malloc<T>::value, "type can be malloc'ed");
134 return (T *) malloc(size);
135 }
136
137 /*
138 * Prevent using `free` on types that are non-POD.
139 *
140 * Declare a delete prototype of free if the parameter type is not safe to free
141 * (non-POD).
142 *
143 * If the parameter is a pointer to void, we can't check if what is pointed
144 * to is safe to free or not, as we don't know what is pointed to. Ideally,
145 * all calls to free would be with a typed pointer, but there are too many
146 * instances of passing a pointer to void to enforce that right now. So allow
147 * pointers to void, these will not be checked.
148 */
149
150 template<typename T>
151 struct can_free
152 {
153 /*
154 * gcc versions before 5.0 lack some type traits defined in C++11.
155 * Since in this instance we use the trait to prevent misuses
156 * of free (and statically assert) and not to generate different
157 * code based on this property, simply set value to true and allow
158 * the code to compile. Anyone using a contemporary compiler will
159 * catch the error.
160 */
161 #if __GNUG__ && __GNUC__ < 5
162 static constexpr bool value = true;
163 #else
164 static constexpr bool value = std::is_trivially_destructible<T>::value || std::is_void<T>::value;
165 #endif
166 };
167
168 template<typename T, typename = typename std::enable_if<!can_free<T>::value>::type>
169 void free(T *p) = delete;
170
171 template<typename T>
172 struct can_memset
173 {
174 static constexpr bool value = std::is_pod<T>::value || std::is_void<T>::value;
175 };
176
177 template <typename T, typename = typename std::enable_if<!can_memset<T>::value>::type>
178 void *memset(T *s, int c, size_t n) = delete;
179
180 template<typename T>
181 struct can_memcpy
182 {
183 /*
184 * gcc versions before 5.0 lack some type traits defined in C++11.
185 * Since in this instance we use the trait to prevent misuses
186 * of memcpy (and statically assert) and not to generate different
187 * code based on this property, simply set value to true and allow
188 * the code to compile. Anyone using a contemporary compiler will
189 * catch the error.
190 */
191 #if __GNUG__ && __GNUC__ < 5
192 static constexpr bool value = true;
193 #else
194 static constexpr bool value = std::is_trivially_copyable<T>::value;
195 #endif
196 };
197
198 template <typename T, typename U,
199 typename = typename std::enable_if<!can_memcpy<T>::value>::type,
200 typename = typename std::enable_if<!can_memcpy<U>::value>::type>
201 void *memcpy(T *d, const U *s, size_t n) = delete;
202
203 template<typename T>
204 struct can_memmove
205 {
206 /*
207 * gcc versions before 5.0 lack some type traits defined in C++11.
208 * Since in this instance we use the trait to prevent misuses
209 * of memmove (and statically assert) and not to generate different
210 * code based on this property, simply set value to true and allow
211 * the code to compile. Anyone using a contemporary compiler will
212 * catch the error.
213 */
214 #if __GNUG__ && __GNUC__ < 5
215 static constexpr bool value = true;
216 #else
217 static constexpr bool value = std::is_trivially_copyable<T>::value;
218 #endif
219 };
220
221 template <typename T, typename U,
222 typename = typename std::enable_if<!can_memmove<T>::value>::type,
223 typename = typename std::enable_if<!can_memmove<U>::value>::type>
224 void *memmove(T *d, const U *s, size_t n) = delete;
225
226 #ifndef ARRAY_SIZE
227 #define ARRAY_SIZE(array) (sizeof(array) / (sizeof((array)[0])))
228 #endif
229
230 #ifndef container_of
231 #define container_of(ptr, type, member) \
232 ({ \
233 const typeof(((type *)NULL)->member) * __ptr = (ptr); \
234 (type *)((char *)__ptr - offsetof(type, member)); \
235 })
236 #endif
237
238 #ifndef LTTNG_PACKED
239 #define LTTNG_PACKED __attribute__((__packed__))
240 #endif
241
242 #ifndef LTTNG_NO_SANITIZE_ADDRESS
243 #if defined(__clang__) || defined (__GNUC__)
244 #define LTTNG_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
245 #else
246 #define LTTNG_NO_SANITIZE_ADDRESS
247 #endif
248 #endif
249
250 #define member_sizeof(type, field) sizeof(((type *) 0)->field)
251
252 #define ASSERT_LOCKED(lock) LTTNG_ASSERT(pthread_mutex_trylock(&lock))
253 #define ASSERT_RCU_READ_LOCKED(lock) LTTNG_ASSERT(rcu_read_ongoing())
254
255 /* Attribute suitable to tag functions as having printf()-like arguments. */
256 #define ATTR_FORMAT_PRINTF(_string_index, _first_to_check) \
257 __attribute__((format(printf, _string_index, _first_to_check)))
258
259 /* Attribute suitable to tag functions as having strftime()-like arguments. */
260 #define ATTR_FORMAT_STRFTIME(_string_index) \
261 __attribute__((format(strftime, _string_index, 0)))
262
263 /* Macros used to ignore specific compiler diagnostics. */
264
265 #define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
266 #define DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
267
268 #if defined(__clang__)
269 /* Clang */
270 # define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT
271 # define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \
272 _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
273 # define DIAGNOSTIC_IGNORE_LOGICAL_OP
274 #else
275 /* GCC */
276 # define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT \
277 _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"")
278 # define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \
279 _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
280 # define DIAGNOSTIC_IGNORE_LOGICAL_OP \
281 _Pragma("GCC diagnostic ignored \"-Wlogical-op\"")
282 #endif
283
284 /* Used to make specific C++ functions to C code. */
285 #ifdef __cplusplus
286 #define C_LINKAGE extern "C"
287 #else
288 #define C_LINKAGE
289 #endif
290
291 /*
292 * lttng_strncpy returns 0 on success, or nonzero on failure.
293 * It checks that the @src string fits into @dst_len before performing
294 * the copy. On failure, no copy has been performed.
295 *
296 * Assumes that 'src' is null-terminated.
297 *
298 * dst_len includes the string's trailing NULL.
299 */
300 static inline
301 int lttng_strncpy(char *dst, const char *src, size_t dst_len)
302 {
303 if (strlen(src) >= dst_len) {
304 /* Fail since copying would result in truncation. */
305 return -1;
306 }
307 strcpy(dst, src);
308 return 0;
309 }
310
311 #endif /* _MACROS_H */
This page took 0.036479 seconds and 4 git commands to generate.