Created
March 17, 2017 14:35
-
-
Save antekone/147f7042b6cba7f77f8c7853178a2f5a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#define NAMESPACE_ENDIANCONVERSION_BEGIN namespace EndianConversion { | |
#define NAMESPACE_ENDIANCONVERSION_END } | |
#include <stdint.h> | |
// __BYTE_ORDER__ is a gcc macro | |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | |
#define __LESWAP(n, x) x | |
#define __BESWAP(n, x) doBSwap ## n(x) | |
#else | |
#define __LESWAP(n, x) doBSwap ## n(x) | |
#define __BESWAP(n, x) x | |
#endif | |
NAMESPACE_ENDIANCONVERSION_BEGIN | |
constexpr uint64_t inC64(uint64_t c) { | |
return ((c >> 32) & 0x00000000FFFFFFFF) | | |
((c << 32) & 0xFFFFFFFF00000000); | |
} | |
constexpr uint64_t inB64(uint64_t b) { | |
return ((b >> 16) & 0x0000FFFF0000FFFF) | | |
((b << 16) & 0xFFFF0000FFFF0000); | |
} | |
constexpr uint64_t inA64(uint64_t a) { | |
return ((a >> 8) & 0x00FF00FF00FF00FF) | | |
((a << 8) & 0xFF00FF00FF00FF00); | |
} | |
constexpr uint32_t inB32(uint32_t b) { | |
return ((b >> 16) & 0x0000FFFF) | | |
((b << 16) & 0xFFFF0000); | |
} | |
constexpr uint32_t inA32(uint32_t a) { | |
return ((a >> 8) & 0x00FF00FF) | | |
((a << 8) & 0xFF00FF00); | |
} | |
constexpr uint16_t inA16(uint16_t a) { | |
return ((a >> 8) & 0x00FF) | | |
((a << 8) & 0xFF00); | |
} | |
// This gets compiled to 1 instruction on g++ -O2 and clang++ -O1, placed | |
// inline in the caller code. | |
// | |
// 31 b: 48 0f c8 bswap %rax | |
constexpr uint64_t doBSwap64(uint64_t in) { return inA64(inB64(inC64(in))); } | |
// 31 b: 48 0f c8 bswap %eax | |
constexpr uint32_t doBSwap32(uint32_t in) { return inA32(inB32(in)); } | |
// 12 b: 66 c1 c0 08 rol $0x8,%ax | |
constexpr uint32_t doBSwap16(uint16_t in) { return inA16(in); } | |
inline uint64_t systemToLittle64(uint64_t in) { return __LESWAP(64, in); } | |
inline uint32_t systemToLittle32(uint32_t in) { return __LESWAP(32, in); } | |
inline uint16_t systemToLittle16(uint16_t in) { return __LESWAP(16, in); } | |
inline uint64_t systemToBig64(uint64_t in) { return __BESWAP(64, in); } | |
inline uint32_t systemToBig32(uint32_t in) { return __BESWAP(32, in); } | |
inline uint16_t systemToBig16(uint16_t in) { return __BESWAP(16, in); } | |
inline uint64_t littleToSystem64(uint64_t in) { return __LESWAP(64, in); } | |
inline uint32_t littleToSystem32(uint32_t in) { return __LESWAP(32, in); } | |
inline uint16_t littleToSystem16(uint16_t in) { return __LESWAP(16, in); } | |
inline uint64_t bigToSystem64(uint64_t in) { return __BESWAP(64, in); } | |
inline uint32_t bigToSystem32(uint32_t in) { return __BESWAP(32, in); } | |
inline uint16_t bigToSystem16(uint16_t in) { return __BESWAP(16, in); } | |
#undef __LIB_LE | |
// If these static_asserts fail, you have a problem with your compiler. | |
static_assert(0x3412 == doBSwap16(0x1234)); | |
static_assert(0x2193 == doBSwap16(0x9321)); | |
static_assert(0x78563412 == doBSwap32(0x12345678)); | |
static_assert(0x21436587 == doBSwap32(0x87654321)); | |
static_assert(0x7856341278563412 == doBSwap64(0x1234567812345678)); | |
static_assert(0x2143658721436587 == doBSwap64(0x8765432187654321)); | |
NAMESPACE_ENDIANCONVERSION_END |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment