1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file declares generic and optimized functions to swap the byte order of
// an integral type.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_SWAPBYTEORDER_H
#define LLVM_SUPPORT_SWAPBYTEORDER_H
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"
#include <cstddef>
#include <type_traits>
#if defined(_MSC_VER) && !defined(_DEBUG)
#include <stdlib.h>
#endif
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__)
#include <endian.h>
#elif defined(_AIX)
#include <sys/machine.h>
#elif defined(__sun)
/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
#include <sys/types.h>
#define BIG_ENDIAN 4321
#define LITTLE_ENDIAN 1234
#if defined(_BIG_ENDIAN)
#define BYTE_ORDER BIG_ENDIAN
#else
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#else
#if !defined(BYTE_ORDER) && !defined(_WIN32)
#include <machine/endian.h>
#endif
#endif
namespace llvm {
namespace sys {
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
constexpr bool IsBigEndianHost = true;
#else
constexpr bool IsBigEndianHost = false;
#endif
static const bool IsLittleEndianHost = !IsBigEndianHost;
/// SwapByteOrder_16 - This function returns a byte-swapped representation of
/// the 16-bit argument.
inline uint16_t SwapByteOrder_16(uint16_t value) {
#if defined(_MSC_VER) && !defined(_DEBUG)
// The DLL version of the runtime lacks these functions (bug!?), but in a
// release build they're replaced with BSWAP instructions anyway.
return _byteswap_ushort(value);
#else
uint16_t Hi = value << 8;
uint16_t Lo = value >> 8;
return Hi | Lo;
#endif
}
/// This function returns a byte-swapped representation of the 32-bit argument.
inline uint32_t SwapByteOrder_32(uint32_t value) {
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
return __builtin_bswap32(value);
#elif defined(_MSC_VER) && !defined(_DEBUG)
return _byteswap_ulong(value);
#else
uint32_t Byte0 = value & 0x000000FF;
uint32_t Byte1 = value & 0x0000FF00;
uint32_t Byte2 = value & 0x00FF0000;
uint32_t Byte3 = value & 0xFF000000;
return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
#endif
}
/// This function returns a byte-swapped representation of the 64-bit argument.
inline uint64_t SwapByteOrder_64(uint64_t value) {
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
return __builtin_bswap64(value);
#elif defined(_MSC_VER) && !defined(_DEBUG)
return _byteswap_uint64(value);
#else
uint64_t Hi = SwapByteOrder_32(uint32_t(value));
uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32));
return (Hi << 32) | Lo;
#endif
}
inline unsigned char getSwappedBytes(unsigned char C) { return C; }
inline signed char getSwappedBytes(signed char C) { return C; }
inline char getSwappedBytes(char C) { return C; }
inline unsigned short getSwappedBytes(unsigned short C) { return SwapByteOrder_16(C); }
inline signed short getSwappedBytes( signed short C) { return SwapByteOrder_16(C); }
inline unsigned int getSwappedBytes(unsigned int C) { return SwapByteOrder_32(C); }
inline signed int getSwappedBytes( signed int C) { return SwapByteOrder_32(C); }
#if __LONG_MAX__ == __INT_MAX__
inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_32(C); }
inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_32(C); }
#elif __LONG_MAX__ == __LONG_LONG_MAX__
inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_64(C); }
inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_64(C); }
#else
#error "Unknown long size!"
#endif
inline unsigned long long getSwappedBytes(unsigned long long C) {
return SwapByteOrder_64(C);
}
inline signed long long getSwappedBytes(signed long long C) {
return SwapByteOrder_64(C);
}
inline float getSwappedBytes(float C) {
union {
uint32_t i;
float f;
} in, out;
in.f = C;
out.i = SwapByteOrder_32(in.i);
return out.f;
}
inline double getSwappedBytes(double C) {
union {
uint64_t i;
double d;
} in, out;
in.d = C;
out.i = SwapByteOrder_64(in.i);
return out.d;
}
template <typename T>
inline typename std::enable_if<std::is_enum<T>::value, T>::type
getSwappedBytes(T C) {
return static_cast<T>(
getSwappedBytes(static_cast<typename std::underlying_type<T>::type>(C)));
}
template<typename T>
inline void swapByteOrder(T &Value) {
Value = getSwappedBytes(Value);
}
} // end namespace sys
} // end namespace llvm
#endif
|