mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 02:35:57 +01:00
Use compiler intrinsics to swap bytes
This commit is contained in:
@@ -62,10 +62,16 @@ INCLUDE(ExternalProject)
|
||||
# Compilation options
|
||||
# *******************
|
||||
|
||||
# Always check for C++ features
|
||||
INCLUDE(CheckCXXFeatures)
|
||||
|
||||
IF(HAS_GCC_BUILTIN_SWAP)
|
||||
SET(HAVE_GCC_BUILTIN_SWAP ON)
|
||||
ENDIF()
|
||||
|
||||
# C++11 support
|
||||
OPTION(LIBTINS_ENABLE_CXX11 "Compile libtins with c++11 features" ON)
|
||||
IF(LIBTINS_ENABLE_CXX11)
|
||||
INCLUDE(CheckCXXFeatures)
|
||||
# We only use declval and decltype on gcc/clang as VC fails to build that code,
|
||||
# at least on VC2013
|
||||
IF(HAS_CXX11_RVALUE_REFERENCES AND ((HAS_CXX11_DECLVAL AND HAS_CXX11_DECLTYPE) OR MSVC))
|
||||
|
||||
@@ -142,3 +142,4 @@ cxx11_check_feature("decltype" HAS_CXX11_DECLTYPE)
|
||||
cxx11_check_feature("declval" HAS_CXX11_DECLVAL)
|
||||
cxx11_check_feature("initializer_list" HAS_CXX11_INITIALIZER_LIST)
|
||||
cxx11_check_feature("rvalue-references" HAS_CXX11_RVALUE_REFERENCES)
|
||||
cxx11_check_feature("builtin-swap" HAS_GCC_BUILTIN_SWAP)
|
||||
|
||||
8
cmake/Modules/CheckCXXFeatures/cxx-test-builtin-swap.cpp
Normal file
8
cmake/Modules/CheckCXXFeatures/cxx-test-builtin-swap.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
int main() {
|
||||
uint16_t u16 = __builtin_bswap16(0x9812U);
|
||||
uint32_t u32 = __builtin_bswap32(0x9812ad81U);
|
||||
uint64_t u64 = __builtin_bswap64(0x9812ad81f61a890dU);
|
||||
return (u16 > 0 && u32 > 0 && u64 > 0) ? 0 : 1;
|
||||
}
|
||||
@@ -16,4 +16,7 @@
|
||||
/* Have TCP ACK tracking */
|
||||
#cmakedefine HAVE_ACK_TRACKER
|
||||
|
||||
/* Have GCC builtin swap */
|
||||
#cmakedefine HAVE_GCC_BUILTIN_SWAP
|
||||
|
||||
#endif // TINS_CONFIG_H
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#define TINS_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
|
||||
#define TINS_IS_BIG_ENDIAN (_BYTE_ORDER == _BIG_ENDIAN)
|
||||
#elif defined(_WIN32)
|
||||
#include <cstdlib>
|
||||
// Assume windows == little endian. fixme later
|
||||
#define TINS_IS_LITTLE_ENDIAN 1
|
||||
#define TINS_IS_BIG_ENDIAN 0
|
||||
@@ -51,6 +52,19 @@
|
||||
#define TINS_IS_BIG_ENDIAN (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
#endif
|
||||
|
||||
// Define macros to swap bytes using compiler intrinsics when possible
|
||||
#if defined(_MSC_VER)
|
||||
#define TINS_BYTE_SWAP_16(data) _byteswap_ushort(data)
|
||||
#define TINS_BYTE_SWAP_32(data) _byteswap_ulong(data)
|
||||
#define TINS_BYTE_SWAP_64(data) _byteswap_uint64(data)
|
||||
#elif defined(HAVE_GCC_BUILTIN_SWAP)
|
||||
#define TINS_BYTE_SWAP_16(data) __builtin_bswap16(data)
|
||||
#define TINS_BYTE_SWAP_32(data) __builtin_bswap32(data)
|
||||
#define TINS_BYTE_SWAP_64(data) __builtin_bswap64(data)
|
||||
#else
|
||||
#define TINS_NO_BYTE_SWAP_INTRINSICS
|
||||
#endif
|
||||
|
||||
namespace Tins {
|
||||
namespace Endian {
|
||||
|
||||
@@ -70,7 +84,11 @@ inline uint8_t do_change_endian(uint8_t data) {
|
||||
* \param data The data to convert.
|
||||
*/
|
||||
inline uint16_t do_change_endian(uint16_t data) {
|
||||
return ((data & 0xff00) >> 8) | ((data & 0x00ff) << 8);
|
||||
#ifdef TINS_NO_BYTE_SWAP_INTRINSICS
|
||||
return ((data & 0xff00) >> 8) | ((data & 0x00ff) << 8);
|
||||
#else
|
||||
return TINS_BYTE_SWAP_16(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,8 +97,12 @@ inline uint16_t do_change_endian(uint16_t data) {
|
||||
* \param data The data to convert.
|
||||
*/
|
||||
inline uint32_t do_change_endian(uint32_t data) {
|
||||
return (((data & 0xff000000) >> 24) | ((data & 0x00ff0000) >> 8) |
|
||||
((data & 0x0000ff00) << 8) | ((data & 0x000000ff) << 24));
|
||||
#ifdef TINS_NO_BYTE_SWAP_INTRINSICS
|
||||
return (((data & 0xff000000) >> 24) | ((data & 0x00ff0000) >> 8) |
|
||||
((data & 0x0000ff00) << 8) | ((data & 0x000000ff) << 24));
|
||||
#else
|
||||
return TINS_BYTE_SWAP_32(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,8 +111,12 @@ inline uint32_t do_change_endian(uint32_t data) {
|
||||
* \param data The data to convert.
|
||||
*/
|
||||
inline uint64_t do_change_endian(uint64_t data) {
|
||||
return (((uint64_t)(do_change_endian((uint32_t)(data & 0xffffffff))) << 32) |
|
||||
(do_change_endian(((uint32_t)(data >> 32)))));
|
||||
#ifdef TINS_NO_BYTE_SWAP_INTRINSICS
|
||||
return (((uint64_t)(do_change_endian((uint32_t)(data & 0xffffffff))) << 32) |
|
||||
(do_change_endian(((uint32_t)(data >> 32)))));
|
||||
#else
|
||||
return TINS_BYTE_SWAP_64(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user