diff options
Diffstat (limited to 'src/uscxml/Convenience.h')
-rw-r--r-- | src/uscxml/Convenience.h | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/uscxml/Convenience.h b/src/uscxml/Convenience.h index 64abbda..f764d06 100644 --- a/src/uscxml/Convenience.h +++ b/src/uscxml/Convenience.h @@ -20,6 +20,8 @@ #ifndef CONVENIENCE_H_LU7GZ6CB #define CONVENIENCE_H_LU7GZ6CB +#include <boost/detail/endian.hpp> + namespace uscxml { inline bool isnan(double x) { return x != x; @@ -57,6 +59,150 @@ inline bool iequals(const std::string& a, const std::string& b) { return true; } +// see http://www.cplusplus.com/forum/general/27544/ + +// Little-endian operating systems: +//--------------------------------- +// Linux on x86, x64, Alpha and Itanium +// Mac OS on x86, x64 +// Solaris on x86, x64, PowerPC +// Tru64 on Alpha +// Windows on x86, x64 and Itanium + +// Big-endian operating systems: +//------------------------------ +// AIX on POWER +// AmigaOS on PowerPC and 680x0 +// HP-UX on Itanium and PA-RISC +// Linux on MIPS, SPARC, PA-RISC, POWER, PowerPC, and 680x0 +// Mac OS on PowerPC and 680x0 +// Solaris on SPARC + +/** +Detect endianness, see http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c +union { + unsigned long long ull; + char c[8]; +} x; +x.ull = 0x0123456789abcdef; // may need special suffix for ULL. +*/ + +enum endianness { + little_endian, + big_endian, + network_endian = big_endian, + +#if defined(BOOST_LITTLE_ENDIAN) + host_endian = little_endian +#elif defined(BOOST_BIG_ENDIAN) + host_endian = big_endian +#else +#error "unable to determine system endianness" +#endif +}; + +namespace detail { + + template<typename T, size_t sz> + struct swap_bytes { + inline T operator()(T val) { + throw std::out_of_range("data size"); + } + }; + + template<typename T> + struct swap_bytes<T, 1> { + inline T operator()(T val) { + return val; + } + }; + + template<typename T> + struct swap_bytes<T, 2> { // for 16 bit + inline T operator()(T val) { + return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8)); + } + }; + + template<typename T> + struct swap_bytes<T, 4> { // for 32 bit + inline T operator()(T val) { +#if defined(_USE_BUILTIN_BSWAPS) && defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4) + return __builtin_bswap32(val); +#else + return ((((val) & 0xff000000) >> 24) | + (((val) & 0x00ff0000) >> 8) | + (((val) & 0x0000ff00) << 8) | + (((val) & 0x000000ff) << 24)); +#endif + } + }; + + template<> + struct swap_bytes<float, 4> { + inline float operator()(float val) { + uint32_t mem = swap_bytes<uint32_t, sizeof(uint32_t)>()(*(uint32_t*)&val); + return *(float*)&mem; + } + }; + + template<typename T> + struct swap_bytes<T, 8> { // for 64 bit + inline T operator()(T val) { +#if defined(_USE_BUILTIN_BSWAPS) && defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4) + return __builtin_bswap64(val); +#else + return ((((val) & 0xff00000000000000ull) >> 56) | + (((val) & 0x00ff000000000000ull) >> 40) | + (((val) & 0x0000ff0000000000ull) >> 24) | + (((val) & 0x000000ff00000000ull) >> 8 ) | + (((val) & 0x00000000ff000000ull) << 8 ) | + (((val) & 0x0000000000ff0000ull) << 24) | + (((val) & 0x000000000000ff00ull) << 40) | + (((val) & 0x00000000000000ffull) << 56)); +#endif + } + }; + + template<> + struct swap_bytes<double, 8> { + inline double operator()(double val) { + uint64_t mem = swap_bytes<uint64_t, sizeof(uint64_t)>()(*(uint64_t*)&val); + return *(double*)&mem; + } + }; + + template<endianness from, endianness to, class T> + struct do_byte_swap { + inline T operator()(T value) { + return swap_bytes<T, sizeof(T)>()(value); + } + }; + // specialisations when attempting to swap to the same endianess + template<class T> struct do_byte_swap<little_endian, little_endian, T> { + inline T operator()(T value) { + return value; + } + }; + template<class T> struct do_byte_swap<big_endian, big_endian, T> { + inline T operator()(T value) { + return value; + } + }; + +} // namespace detail + +template<endianness from, endianness to, class T> +inline T byte_swap(T value) { + // ensure the data is only 1, 2, 4 or 8 bytes + BOOST_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8); + // ensure we're only swapping arithmetic types + BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value); + + return detail::do_byte_swap<from, to, T>()(value); +} + + } |