summaryrefslogtreecommitdiff
path: root/src/macros.h
blob: 659d471912c5791ef6d2471d56e6a1719f73ce68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * Copyright (c) 2001-2022 The strace developers.
 * All rights reserved.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#ifndef STRACE_MACROS_H
# define STRACE_MACROS_H

# include <stdbool.h>
# include <stddef.h>
# include <sys/types.h>

# include "gcc_compat.h"
# include "static_assert.h"

/*
 * Evaluates to:
 * a syntax error, if the argument is 0;
 * 0, otherwise.
 */
# define FAIL_BUILD_ON_ZERO(e_)	(sizeof(int[-1 + 2 * !!(e_)]) * 0)

/*
 * Evaluates to:
 * 1, if the given type is known to be a non-array type;
 * 0, otherwise.
 */
# define IS_NOT_ARRAY(a_)	IS_SAME_TYPE((a_), &(a_)[0])

/*
 * Evaluates to:
 * a syntax error, if the argument is not an array;
 * 0, otherwise.
 */
# define MUST_BE_ARRAY(a_)	FAIL_BUILD_ON_ZERO(!IS_NOT_ARRAY(a_))

/* Evaluates to the number of elements in the specified array.  */
# define ARRAY_SIZE(a_)	(sizeof(a_) / sizeof((a_)[0]) + MUST_BE_ARRAY(a_))

# define ARRSZ_PAIR(a_) a_, ARRAY_SIZE(a_)

# define STRINGIFY(...)		#__VA_ARGS__
# define STRINGIFY_VAL(...)	STRINGIFY(__VA_ARGS__)

# ifndef MAX
#  define MAX(a, b)		(((a) > (b)) ? (a) : (b))
# endif
# ifndef MIN
#  define MIN(a, b)		(((a) < (b)) ? (a) : (b))
# endif
# define CLAMP(val, min, max)	MIN(MAX(val, min), max)

# ifndef ROUNDUP_DIV
#  define ROUNDUP_DIV(val_, div_) (((val_) + (div_) - 1) / (div_))
# endif

# ifndef ROUNDUP
#  define ROUNDUP(val_, div_) (ROUNDUP_DIV((val_), (div_)) * (div_))
# endif

# define sizeof_field(type_, member_) (sizeof(((type_ *)0)->member_))

# define typeof_field(type_, member_) typeof(((type_ *)0)->member_)

# ifndef offsetofend
#  define offsetofend(type_, member_)	\
	(offsetof(type_, member_) + sizeof_field(type_, member_))
# endif

# ifndef cast_ptr
#  define cast_ptr(type_, var_)	\
	((type_) (uintptr_t) (const volatile void *) (var_))
# endif

# ifndef containerof
/**
 * Return a pointer to a structure that contains the provided variable.
 *
 * @param ptr_    Pointer to data that is a field of the container structure.
 * @param struct_ Type of the container structure.
 * @param member_ Name of the member field.
 * @return  Pointer to the container structure.
 */
#  define containerof(ptr_, struct_, member_)	\
	cast_ptr(struct_ *,			\
		 (const volatile char *) (ptr_) - offsetof(struct_, member_))
# endif

static inline bool
is_filled(const char *ptr, char fill, size_t size)
{
	while (size--)
		if (*ptr++ != fill)
			return false;

	return true;
}

# define IS_ARRAY_ZERO(arr_)	\
	is_filled((const char *) (arr_), 0, sizeof(arr_) + MUST_BE_ARRAY(arr_))

# ifndef BIT32
#  define BIT32(x_) (1U << (x_))
# endif

# ifndef BIT64
#  define BIT64(x_) (1ULL << (x_))
# endif

# ifndef MASK32
#  define MASK32(x_) (BIT32(x_) - 1U)
# endif

# ifndef MASK64
#  define MASK64(x_) (BIT64(x_) - 1ULL)
# endif

/*
 * "Safe" versions that avoid UB for values that are >= type bit size
 * (the usually expected behaviour of the bit shift in that case is zero,
 * but at least powerpc is notorious for returning the input value when shift
 * by 64 bits is performed).
 */

# define BIT32_SAFE(x_) ((x_) < 32 ? BIT32(x_) : 0)
# define BIT64_SAFE(x_) ((x_) < 64 ? BIT64(x_) : 0)
# define MASK32_SAFE(x_) (BIT32_SAFE(x_) - 1U)
# define MASK64_SAFE(x_) (BIT64_SAFE(x_) - 1ULL)

# define FLAG(name_) name_ = BIT32(name_##_BIT)

/**
 * A shorthand for a build-time check of a type size that provides
 * a corresponding "update the decoder" message in a case of failure.
 * @param type_ Type whose size is to be checked.
 * @param sz_   Expected type size in bytes.
 */
# define CHECK_TYPE_SIZE(type_, sz_) \
	static_assert(sizeof(type_) == (sz_), \
		      "Unexpected size of " #type_ "(" #sz_ " expected)")

/** Checks that ioctl code's size field contains the expected value. */
#define CHECK_IOCTL_SIZE(ioc_, sz_) \
	static_assert(_IOC_SIZE(ioc_) == (sz_), \
		"Unexpected size field value in " #ioc_ " (" #sz_" expected)")

# ifdef WORDS_BIGENDIAN
#  define BE16(val_) val_
#  define BE32(val_) val_
#  define BE64(val_) val_
# else
#  define BE16(val_) ((((val_) & 0xff) << 8) | (((val_) >> 8) & 0xff))
#  define BE32(val_) ((BE16(val_) << 16) | BE16((val_) >> 16))
#  define BE64(val_) ((BE32(val_) << 32) | BE32((val_) >> 32))
# endif

#endif /* !STRACE_MACROS_H */