diff options
Diffstat (limited to 'reorder.h')
| -rw-r--r-- | reorder.h | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/reorder.h b/reorder.h new file mode 100644 index 0000000..5cb546b --- /dev/null +++ b/reorder.h @@ -0,0 +1,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 |
