Mercurial > minori
view include/core/endian.h @ 364:99c961c91809
core: refactor out byte stream into its own file
easy dubs
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Tue, 16 Jul 2024 21:15:59 -0400 |
parents | 9aaf1e788896 |
children |
line wrap: on
line source
#ifndef MINORI_CORE_ENDIAN_H_ #define MINORI_CORE_ENDIAN_H_ /* definition of endian-related stuff. primarily used for x11 * binary structures */ #include "core/bit_cast.h" #include <cstdint> #include <type_traits> class Endian { private: /* check for compiler builtins for byteswapping */ #ifdef __has_builtin # if __has_builtin(__builtin_bswap16) # define COMPILER_BUILTIN_BSWAP16(x) __builtin_bswap16(x) # endif # if __has_builtin(__builtin_bswap32) # define COMPILER_BUILTIN_BSWAP32(x) __builtin_bswap32(x) # endif # if __has_builtin(__builtin_bswap64) # define COMPILER_BUILTIN_BSWAP64(x) __builtin_bswap64(x) # endif #endif static constexpr uint16_t byteswap_16(uint16_t x) { #ifdef COMPILER_BUILTIN_BSWAP16 return COMPILER_BUILTIN_BSWAP16(x); #else return ( ((x & UINT16_C(0x00FF)) << 8) | ((x & UINT16_C(0xFF00)) >> 8) ); #endif } static constexpr uint32_t byteswap_32(uint32_t x) { #ifdef COMPILER_BUILTIN_BSWAP32 return COMPILER_BUILTIN_BSWAP32(x); #else return ( ((x & UINT32_C(0x000000FF)) << 24) | ((x & UINT32_C(0x0000FF00)) << 8) | ((x & UINT32_C(0x00FF0000)) >> 8) | ((x & UINT32_C(0xFF000000)) >> 24) ); #endif } static constexpr uint64_t byteswap_64(uint64_t x) { #ifdef COMPILER_BUILTIN_BSWAP64 return COMPILER_BUILTIN_BSWAP64(x); #else return ( ((x & UINT64_C(0x00000000000000FF)) << 56) | ((x & UINT64_C(0x000000000000FF00)) << 40) | ((x & UINT64_C(0x0000000000FF0000)) << 24) | ((x & UINT64_C(0x00000000FF000000)) << 8) | ((x & UINT64_C(0x000000FF00000000)) >> 8) | ((x & UINT64_C(0x0000FF0000000000)) >> 24) | ((x & UINT64_C(0x00FF000000000000)) >> 40) | ((x & UINT64_C(0xFF00000000000000)) >> 56) ); #endif } #ifdef COMPILER_BUILTIN_BSWAP16 # undef COMPILER_BUILTIN_BSWAP16 #endif #ifdef COMPILER_BUILTIN_BSWAP32 # undef COMPILER_BUILTIN_BSWAP32 #endif #ifdef COMPILER_BUILTIN_BSWAP64 # undef COMPILER_BUILTIN_BSWAP64 #endif public: #if defined(BYTE_ORDER_BIG) static constexpr bool big = true; static constexpr bool little = false; #elif defined(BYTE_ORDER_LITTLE) static constexpr bool big = false; static constexpr bool little = true; #else #error "unsupported endianness" #endif template<typename T> static constexpr T byteswap(T x) { static_assert(std::is_integral<T>::value); static_assert(std::is_unsigned<T>::value, "use signed_byteswap"); if constexpr (std::is_same<T, uint8_t>::value) { return x; } else if constexpr (std::is_same<T, uint16_t>::value) { return byteswap_16(x); } else if constexpr (std::is_same<T, uint32_t>::value) { return byteswap_32(x); } else if constexpr (std::is_same<T, uint64_t>::value) { return byteswap_64(x); } else { static_assert(!sizeof(T), "invalid integer type given to byteswap"); } } /* this can't be constexpr */ template<typename T> static T signed_byteswap(T x) { static_assert(std::is_integral<T>::value); static_assert(std::is_signed<T>::value, "use regular byteswap"); using uT = typename std::make_unsigned<T>::type; return minori::BitCast<T, uT>(byteswap<uT>(minori::BitCast<uT, T>(x))); } template<typename T> static constexpr T byteswap_little_to_host(T x) { if constexpr (little) { return x; } else if constexpr (big) { return byteswap(x); } } template<typename T> static constexpr T byteswap_big_to_host(T x) { if constexpr (big) { return x; } else if constexpr (little) { return byteswap(x); } } template<typename T> static T signed_byteswap_little_to_host(T x) { if constexpr (little) { return x; } else if constexpr (big) { return signed_byteswap(x); } } template<typename T> static T signed_byteswap_big_to_host(T x) { if constexpr (big) { return x; } else if constexpr (little) { return signed_byteswap(x); } } private: Endian() = delete; }; #endif /* MINORI_CORE_ENDIAN_H_ */