From eb29dec24d1c2a730cec9f804d9254bd53c67f94 Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Fri, 20 Jun 2014 23:19:49 +0300 Subject: [PATCH] bits,endian: stop depending on libc Instead try to get compiler involved. endian: add host-endian enc/dec functions. --- usual/bits.h | 102 +++++++++++--------- usual/endian.h | 245 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 258 insertions(+), 89 deletions(-) diff --git a/usual/bits.h b/usual/bits.h index 76fdd54..a2e9082 100644 --- a/usual/bits.h +++ b/usual/bits.h @@ -31,7 +31,7 @@ #include /** Checks if integer has only one bit set */ -static inline int is_power_of_2(int n) +static inline bool is_power_of_2(unsigned int n) { return (n > 0) && !(n & (n - 1)); } @@ -73,11 +73,18 @@ static inline uint64_t ror64(uint64_t v, int s) { return rol64(v, 64 - s); } * find MSB bit set, 1-based ofs, 0 if arg == 0 */ -#if defined(__GNUC__) && (__GNUC__ >= 4) -#define _FLS(sfx, type) \ +#undef fls +#undef flsl +#undef flsll +#define fls(x) usual_fls(x) +#define flsl(x) usual_flsl(x) +#define flsll(x) usual_flsll(x) + +#if _COMPILER_GNUC(4,0) || __has_builtin(__builtin_clzll) +#define _USUAL_FLS_(sfx, type) \ return (x == 0) ? 0 : ((8*sizeof(type)) - __builtin_clz ## sfx(x)) #else -#define _FLS(sfx, type) \ +#define _USUAL_FLS_(sfx, type) \ unsigned type u = x; \ unsigned int bit; \ if (x == 0) return 0; \ @@ -86,22 +93,25 @@ static inline uint64_t ror64(uint64_t v, int s) { return rol64(v, 64 - s); } return bit #endif -#ifndef HAVE_FLS -#define fls(x) usual_fls(x) -/** Compat: Find last (MSB) set bit, 1-based ofs, 0 if arg == 0 */ -static inline int fls(int x) { _FLS(, int); } -#endif -#ifndef HAVE_FLSL -#define flsl(x) usual_flsl(x) -/** Compat: Find last (MSB) set bit, 1-based ofs, 0 if arg == 0 */ -static inline int flsl(long x) { _FLS(l, long); } -#endif -#ifndef HAVE_FLSLL -#define flsll(x) usual_flsll(x) -/** Compat: Find last (MSB) set bit, 1-based ofs, 0 if arg == 0 */ -static inline int flsll(long long x) { _FLS(ll, long long); } -#endif -#undef _FLS +/** Find last (highest) set bit, 1-based offset, 0 if arg == 0 */ +static inline int fls(int x) +{ + _USUAL_FLS_(, int); +} + +/** Find last (highest) set bit, 1-based offset, 0 if arg == 0 */ +static inline int flsl(long x) +{ + _USUAL_FLS_(l, long); +} + +/** Find last (highest) set bit, 1-based offset, 0 if arg == 0 */ +static inline int flsll(long long x) +{ + _USUAL_FLS_(ll, long long); +} + +#undef _USUAL_FLS_ /* * ffs(int) @@ -111,37 +121,45 @@ static inline int flsll(long long x) { _FLS(ll, long long); } * find LSB bit set, 1-based ofs, 0 if arg == 0 */ -#if defined(__GNUC__) && (__GNUC__ >= 4) -#define _FFS(sfx, type) \ +#undef ffs +#undef ffsl +#undef ffsll +#define ffs(x) usual_ffs(x) +#define ffsl(x) usual_ffsl(x) +#define ffsll(x) usual_ffsll(x) + +#if _COMPILER_GNUC(4,0) || __has_builtin(__builtin_ffsll) +#define _USUAL_FFS_(sfx, type) \ return __builtin_ffs ## sfx((unsigned type)(x)) #else -#define _FFS(sfx, type) \ +#define _USUAL_FFS_(sfx, type) \ unsigned int bit; \ unsigned type u = x; \ if (!x) return 0; \ /* count from smallest bit, assuming small values */ \ - for (bit = 1; !(u & 1); bit++) { \ - u >>= 1; \ - } \ + for (bit = 1; !(u & 1); bit++) u >>= 1; \ return bit #endif -#ifndef HAVE_FFS -#define ffs(x) usual_ffs(x) -/** Compat: Find first (LSB) set bit, 1-based ofs, 0 if arg == 0 */ -static inline int ffs(int x) { _FFS(, int); } -#endif -#ifndef HAVE_FFSL -#define ffsl(x) usual_ffsl(x) -/** Compat: Find first (LSB) set bit, 1-based ofs, 0 if arg == 0 */ -static inline int ffsl(long x) { _FFS(l, long); } -#endif -#ifndef HAVE_FFSLL -#define ffsll(x) usual_ffsll(x) -/** Compat: Find first (LSB) set bit, 1-based ofs, 0 if arg == 0 */ -static inline int ffsll(long long x) { _FFS(ll, long long); } -#endif -#undef _FFS +/** Find first (lowest) set bit, 1-based ofs, 0 if arg == 0 */ +static inline int ffs(int x) +{ + _USUAL_FFS_(, int); +} + +/** Find first (lowest) set bit, 1-based ofs, 0 if arg == 0 */ +static inline int ffsl(long x) +{ + _USUAL_FFS_(l, long); +} + +/** Find first (lowest) set bit, 1-based ofs, 0 if arg == 0 */ +static inline int ffsll(long long x) +{ + _USUAL_FFS_(ll, long long); +} + +#undef _USUAL_FFS_ /* * Multiply and check overflow. diff --git a/usual/endian.h b/usual/endian.h index 27d7904..58d44e2 100644 --- a/usual/endian.h +++ b/usual/endian.h @@ -17,13 +17,19 @@ /** * @file * - * Endianess conversion macros. + * Endianess conversion, convert integers to bytes. */ #ifndef _USUAL_ENDIAN_H_ #define _USUAL_ENDIAN_H_ #include +#include + +/* + * Need to include OS headers even if unused, so our + * definitions stay in use. + */ #ifdef HAVE_ENDIAN_H #include @@ -35,188 +41,333 @@ #include #endif -#include + +/* + * Ignore OS defines, as they may define only some subset of functions. + * + * Instead try to use compiler builtins. + */ + +#undef bswap16 +#undef bswap32 +#undef bswap64 + +#undef htobe16 +#undef htobe32 +#undef htobe64 +#undef htole16 +#undef htole32 +#undef htole64 +#undef be16toh +#undef be32toh +#undef be64toh +#undef le16toh +#undef le32toh +#undef le64toh + +#undef be16dec +#undef be32dec +#undef be64dec +#undef le16dec +#undef le32dec +#undef le64dec +#undef h16dec +#undef h32dec +#undef h64dec + +#undef be16enc +#undef be32enc +#undef be64enc +#undef le16enc +#undef le32enc +#undef le64enc +#undef h16enc +#undef h32enc +#undef h64enc + +/* + * Redefine to avoid conflicts. + */ + +#define bswap16(x) usual_bswap16(x) +#define bswap32(x) usual_bswap32(x) +#define bswap64(x) usual_bswap64(x) + +#define be16dec(p) usual_be16dec(p) +#define be32dec(p) usual_be32dec(p) +#define be64dec(p) usual_be64dec(p) +#define le16dec(p) usual_le16dec(p) +#define le32dec(p) usual_le32dec(p) +#define le64dec(p) usual_le64dec(p) +#define h16dec(p) usual_h16dec(p) +#define h32dec(p) usual_h32dec(p) +#define h64dec(p) usual_h64dec(p) + +#define be16enc(p, x) usual_be16enc(p, x) +#define be32enc(p, x) usual_be32enc(p, x) +#define be64enc(p, x) usual_be64enc(p, x) +#define le16enc(p, x) usual_le16enc(p, x) +#define le32enc(p, x) usual_le32enc(p, x) +#define le64enc(p, x) usual_le64enc(p, x) +#define h16enc(p, x) usual_h16enc(p, x) +#define h32enc(p, x) usual_h32enc(p, x) +#define h64enc(p, x) usual_h64enc(p, x) /** * @name Always swap. + * * @{ */ -#ifndef bswap16 -#ifdef bswap_16 -#define bswap16(x) bswap_16(x) -#else +/** Swap 16-bit int */ static inline uint16_t bswap16(uint16_t x) { +#if _COMPILER_GNUC(4, 8) || __has_builtin(__builtin_bswap16) + return __builtin_bswap16(x); +#else return (x << 8) | (x >> 8); -} -#endif #endif +} -#ifndef bswap32 -#ifdef bswap_32 -#define bswap32(x) bswap_32(x) -#else +/** Swap 32-bit int */ static inline uint32_t bswap32(uint32_t x) { -#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))) +#if _COMPILER_GNUC(4, 3) || __has_builtin(__builtin_bswap32) return __builtin_bswap32(x); #else x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF); return (x << 16) | (x >> 16); #endif } -#endif -#endif -#ifndef bswap64 -#ifdef bswap_64 -#define bswap64(x) bswap_64(x) -#else +/** Swap 64-bit int */ static inline uint64_t bswap64(uint64_t x) { +#if _COMPILER_GNUC(4, 3) || __has_builtin(__builtin_bswap64) + return __builtin_bswap64(x); +#else return ((uint64_t)bswap32(x) << 32) | bswap32(x >> 32); -} #endif -#endif - -/* @} */ +} /** - * @name Host <-> LE/BE + * @} + * + * @name Convert host-endian int to BE/LE. + * * @{ */ -/* Ignore OS defines, as they may define only some subset of functions */ -#undef htobe16 -#undef htobe32 -#undef htobe64 -#undef htole16 -#undef htole32 -#undef htole64 -#undef be16toh -#undef be32toh -#undef be64toh -#undef le16toh -#undef le32toh -#undef le64toh - #ifdef WORDS_BIGENDIAN +/** Convert native 16-bit int to big-endian */ #define htobe16(x) ((uint16_t)(x)) +/** Convert native 32-bit int to big-endian */ #define htobe32(x) ((uint32_t)(x)) +/** Convert native 64-bit int to big-endian */ #define htobe64(x) ((uint64_t)(x)) + +/** Convert native 16-bit int to little-endian */ #define htole16(x) bswap16(x) +/** Convert native 32-bit int to little-endian */ #define htole32(x) bswap32(x) +/** Convert native 64-bit int to little-endian */ #define htole64(x) bswap64(x) +/** Convert big-endian 16-bit int to host-endian */ #define be16toh(x) ((uint16_t)(x)) +/** Convert big-endian 32-bit int to host-endian */ #define be32toh(x) ((uint32_t)(x)) +/** Convert big-endian 64-bit int to host-endian */ #define be64toh(x) ((uint64_t)(x)) + +/** Convert little-endian 16-bit int to host-endian */ #define le16toh(x) bswap16(x) +/** Convert little-endian 32-bit int to host-endian */ #define le32toh(x) bswap32(x) +/** Convert little-endian 64-bit int to host-endian */ #define le64toh(x) bswap64(x) -#else +#else /* !WORDS_BIGENDIAN */ +/** Convert native 16-bit int to big-endian */ #define htobe16(x) bswap16(x) +/** Convert native 32-bit int to big-endian */ #define htobe32(x) bswap32(x) +/** Convert native 64-bit int to big-endian */ #define htobe64(x) bswap64(x) +/** Convert native 16-bit int to little-endian */ #define htole16(x) ((uint16_t)(x)) +/** Convert native 32-bit int to little-endian */ #define htole32(x) ((uint32_t)(x)) +/** Convert native 64-bit int to little-endian */ #define htole64(x) ((uint64_t)(x)) +/** Convert big-endian 16-bit int to host-endian */ #define be16toh(x) bswap16(x) +/** Convert big-endian 32-bit int to host-endian */ #define be32toh(x) bswap32(x) +/** Convert big-endian 64-bit int to host-endian */ #define be64toh(x) bswap64(x) + +/** Convert little-endian 64-bit int to host-endian */ #define le16toh(x) ((uint16_t)(x)) +/** Convert little-endian 64-bit int to host-endian */ #define le32toh(x) ((uint32_t)(x)) +/** Convert little-endian 64-bit int to host-endian */ #define le64toh(x) ((uint64_t)(x)) #endif -/* @} */ - -#ifndef HAVE_ENCDEC_FUNCS - /** - * @name Read LE/BE values from memory and convert to host format + * @} + * + * @name Read integer values from memory and convert to host format. + * * @{ */ + +/** Read big-endian 16-bit int from memory */ static inline uint16_t be16dec(const void *p) { uint16_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htobe16(tmp); } + +/** Read big-endian 32-bit int from memory */ static inline uint32_t be32dec(const void *p) { uint32_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htobe32(tmp); } + +/** Read big-endian 64-bit int from memory */ static inline uint64_t be64dec(const void *p) { uint64_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htobe64(tmp); } + +/** Read little-endian 16-bit int from memory */ static inline uint16_t le16dec(const void *p) { uint16_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htole16(tmp); } + +/** Read little-endian 32-bit int from memory */ static inline uint32_t le32dec(const void *p) { uint32_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htole32(tmp); } + +/** Read little-endian 64-bit int from memory */ static inline uint64_t le64dec(const void *p) { uint64_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htole64(tmp); } -/* @} */ + +/** Read host-endian 16-bit int from memory */ +static inline uint16_t h16dec(const void *p) +{ + uint16_t tmp; + memcpy(&tmp, p, sizeof(tmp)); + return tmp; +} + +/** Read host-endian 32-bit int from memory */ +static inline uint32_t h32dec(const void *p) +{ + uint32_t tmp; + memcpy(&tmp, p, sizeof(tmp)); + return tmp; +} + +/** Read host-endian 64-bit int from memory */ +static inline uint64_t h64dec(const void *p) +{ + uint64_t tmp; + memcpy(&tmp, p, sizeof(tmp)); + return tmp; +} /** + * @} + * * @name Convert host value to LE/BE and write to memory + * * @{ */ + +/** Write big-endian 16-bit int to memory */ static inline void be16enc(void *p, uint16_t x) { uint16_t tmp = htobe16(x); memcpy(p, &tmp, sizeof(tmp)); } + +/** Write big-endian 32-bit int to memory */ static inline void be32enc(void *p, uint32_t x) { uint32_t tmp = htobe32(x); memcpy(p, &tmp, sizeof(tmp)); } + +/** Write big-endian 64-bit int to memory */ static inline void be64enc(void *p, uint64_t x) { uint64_t tmp = htobe64(x); memcpy(p, &tmp, sizeof(tmp)); } + +/** Write little-endian 16-bit int to memory */ static inline void le16enc(void *p, uint16_t x) { uint16_t tmp = htole16(x); memcpy(p, &tmp, sizeof(tmp)); } + +/** Write little-endian 32-bit int to memory */ static inline void le32enc(void *p, uint32_t x) { uint32_t tmp = htole32(x); memcpy(p, &tmp, sizeof(tmp)); } + +/** Write little-endian 64-bit int to memory */ static inline void le64enc(void *p, uint64_t x) { uint64_t tmp = htole64(x); memcpy(p, &tmp, sizeof(tmp)); } -/* @} */ -#endif /* !HAVE_ENCDEC_FUNCS */ +/** Write host-endian 16-bit int to memory */ +static inline void h16enc(void *p, uint16_t x) +{ + memcpy(p, &x, sizeof(x)); +} + +/** Write host-endian 32-bit int to memory */ +static inline void h32enc(void *p, uint32_t x) +{ + memcpy(p, &x, sizeof(x)); +} + +/** Write host-endian 64-bit int to memory */ +static inline void h64enc(void *p, uint64_t x) +{ + memcpy(p, &x, sizeof(x)); +} + +/** @} */ + #endif /* _USUAL_ENDIAN_H_ */ -- 2.39.5