← Back to davo.co
summaryrefslogtreecommitdiffstats
path: root/reorder.h
blob: 5cb546ba10989e2cd5cd350acde34e0350c5ccb6 (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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#ifndef __REORDER_H__
#define __REORDER_H__

#include <string.h>
#include <stdlib.h>

#define rodr_convert(T, ...) (T){ (__VA_ARGS__), }

[[__maybe_unused__]]
static inline
void* rodr_memcpy(size_t n,
                  unsigned char s1[restrict static n],
                  unsigned char const s2[restrict static n])
  [[__unsequenced__]];

[[__maybe_unused__]]
static inline
void* rodr_memccpy(size_t n,
                   unsigned char s1[restrict static n],
                   unsigned char const s2[restrict static n],
                   int c)
  [[__unsequenced__]];

[[__maybe_unused__]]
static inline
void* rodr_memmove(size_t n,
                   unsigned char s1[static n],
                   unsigned char const s2[static n]);

[[__maybe_unused__]]
static inline
int rodr_memcmp(size_t n,
                unsigned char s1[restrict static n],
                unsigned char const s2[restrict static n])
  [[__unsequenced__]];

[[__maybe_unused__]]
static inline
void* rodr_memchr(size_t n, unsigned char const s[static n], int c)
  [[__unsequenced__]];

[[__maybe_unused__]]
static inline
void* rodr_memset(size_t n, unsigned char s[static n], int c)
  [[__unsequenced__]];

[[__maybe_unused__]]
static inline
void rodr_qsort(size_t nmemb, size_t size,
                unsigned char base[static nmemb*size],
                int (*compar)(const void *, const void *));

[[__maybe_unused__]]
static inline
void* rodr_bsearch(size_t nmemb, size_t size,
                   unsigned char const key[static 1],
                   unsigned char const base[static nmemb*size],
                   int (*compar)(const void *, const void *));

/**
 ** @brief Similar to `memcpy` but checks the buffer argument for the
 ** size.
 **
 ** To be able to do that check, the function has the size argument
 ** first and then the buffer, so the buffer can be specified as array
 ** parameter that depends on the that size.
 **
 ** Here there is an additional complication, namely that the original
 ** functions has `void` pointers. We go around this by using
 ** `unsigned char` (which then can be the base of an array). Then, in
 ** the macro interface we have to convert the arguments to `void`
 ** pointers such that this function here can be called without
 ** troubles.
 **/
static inline
void* rodr_memcpy(size_t n,
                  unsigned char s1[restrict static n],
                  unsigned char const s2[restrict static n]) {
  // This captures a possible pre-existing macro for memcpy
  return memcpy(s1, s2, n);
}

static inline
void* rodr_memccpy(size_t n,
                   unsigned char s1[restrict static n],
                   unsigned char const s2[restrict static n],
                   int c) {
  // This captures a possible pre-existing macro for memccpy
  return memccpy(s1, s2, c, n);
}

static inline
void* rodr_memmove(size_t n,
                   unsigned char s1[static n],
                   unsigned char const s2[static n]) {
  // This captures a possible pre-existing macro for memmove
  return memmove(s1, s2, n);
}

static inline
int rodr_memcmp(size_t n,
                unsigned char s1[restrict static n],
                unsigned char const s2[restrict static n]) {
  // This captures a possible pre-existing macro for memcmp
  return memcmp(s1, s2, n);
}


static inline
void* rodr_memchr(size_t n, unsigned char const s[static n], int c) {
  // This avoids a possible pre-existing macro for memchr
  return (memchr)(s, c, n);
}

static inline
void* rodr_memset(size_t n, unsigned char s[static n], int c) {
  // This captures a possible pre-existing macro for memset
  return memset(s, c, n);
}


static inline
void rodr_qsort(size_t nmemb, size_t size,
                unsigned char base[static nmemb*size],
                int (*compar)(const void *, const void *)) {
  // This captures a possible pre-existing macro for qsort
  qsort(base, nmemb, size, compar);
}

static inline
void* rodr_bsearch(size_t nmemb, size_t size,
                   unsigned char const key[static 1],
                   unsigned char const base[static nmemb*size],
                   int (*compar)(const void *, const void *)) {
  // This avoids a possible pre-existing macro for bsearch
  return (bsearch)(key, base, nmemb, size, compar);
}

#undef memcpy
/**
 ** @brief A macro replacement for `memcpy` that also propagates the
 ** requirements for the size of the buffer arguments.
 **
 ** There is a complication, namely that the original functions has
 ** `void` pointers. We go around this by using `unsigned char` (which
 ** then can be the base of an array) in the `rodr_memcpy`
 ** interface. So here we have to convert the arguments to `void`
 ** pointers such that this function can be called without troubles.
 **
 ** We don't want to use simple casts to `void*`, for example, because
 ** that would cast away all other type checks that we still want to
 ** maintain. Therefore we use compound literals where the arguments
 ** are initializers. By that, only an argument type that has an
 ** implicit conversion to the corresponding `void` pointer type can
 ** be used, all others will be diagnosed.
 **/
#define memcpy(S1, S2, N)                               \
rodr_memcpy((N),                                        \
            /* Make sure no qualification gets lost */  \
            rodr_convert(void*, S1),                    \
            /* Make sure no volatile gets lost */       \
            rodr_convert(void const*, S2))

#undef memccpy
#define memccpy(S1, S2, C, N)                                   \
  rodr_memccpy((N),                                             \
               /* Make sure no qualification gets lost */       \
               rodr_convert(void*, S1),                         \
               /* Make sure no volatile gets lost */            \
               rodr_convert(void const*, S2),                   \
               (C))

#define memmove(S1, S2, N)                                      \
  rodr_memmove((N),                                             \
               /* Make sure no qualification gets lost */       \
               rodr_convert(void*, S1),                         \
               /* Make sure no volatile gets lost */            \
                 rodr_convert(void const*, S2))

#define memcmp(S1, S2, N)                                       \
  rodr_memcmp((N),                                              \
              /* Make sure no qualification gets lost */        \
              rodr_convert(void*, S1),                          \
              /* Make sure no volatile gets lost */             \
              rodr_convert(void const*, S2))


#undef memchr
#define memchr(S, C, N)                                 \
  ((typeof(1 ? (S) : (void*)1))                         \
   rodr_memchr((N),                                     \
               /* Make sure no volatile gets lost */    \
               rodr_convert(void const*, S),            \
               (C)))

#undef memset
#define memset(S, C, N)                                         \
  rodr_memset((N),                                              \
              /* Make sure no qualification gets lost */        \
              rodr_convert(void*, S),                           \
              (C))

#undef qsort
#define qsort(BASE, NMEMB, SIZE, COMPAR)                \
  rodr_qsort((NMEMB),                                   \
             (SIZE),                                    \
             /* Make sure no qualification gets lost */ \
             rodr_convert(void*, BASE),                 \
             (COMPAR))

#undef bsearch
#define bsearch(KEY, BASE, NMEMB, SIZE, COMPAR)         \
  ((typeof(1 ? (BASE) : (void*)1))                      \
  rodr_bsearch((NMEMB),                                 \
               (SIZE),                                  \
               /* Make sure no volatile gets lost */    \
               rodr_convert(void const*, KEY),          \
               /* Make sure no volatile gets lost */    \
               rodr_convert(void const*, BASE),         \
               (COMPAR)))

#if __STDC_VERSION__ >= 202311L

[[__maybe_unused__]]
static inline
void* rodr_memset_explicit(size_t n, unsigned char s[static n], int c)
  [[__unsequenced__]];

static inline
void* rodr_memset_explicit(size_t n, unsigned char s[static n], int c) {
  // This captures a possible pre-existing macro for memset_explicit
  return memset_explicit(s, c, n);
}

#undef memset_explicit
#define memset_explicit(S, C, N)                                        \
  rodr_memset_explicit((N),                                             \
                       /* Make sure no qualification gets lost */       \
                       rodr_convert(void*, S),                          \
                       (C))

#endif


#endif