diff options
Diffstat (limited to 'src/mongo/platform/endian.h')
-rw-r--r-- | src/mongo/platform/endian.h | 567 |
1 files changed, 85 insertions, 482 deletions
diff --git a/src/mongo/platform/endian.h b/src/mongo/platform/endian.h index 4d367baf89b..5a36f783ce0 100644 --- a/src/mongo/platform/endian.h +++ b/src/mongo/platform/endian.h @@ -31,509 +31,112 @@ #include <climits> #include <cstdint> +#include <cstdlib> #include <cstring> #include <type_traits> - -#include "mongo/base/static_assert.h" -#include "mongo/config.h" -#include "mongo/platform/decimal128.h" - -#pragma push_macro("MONGO_UINT16_SWAB") -#pragma push_macro("MONGO_UINT32_SWAB") -#pragma push_macro("MONGO_UINT64_SWAB") -#pragma push_macro("htobe16") -#pragma push_macro("htobe32") -#pragma push_macro("htobe64") -#pragma push_macro("htole16") -#pragma push_macro("htole32") -#pragma push_macro("htole64") -#pragma push_macro("be16toh") -#pragma push_macro("be32toh") -#pragma push_macro("be64toh") -#pragma push_macro("le16toh") -#pragma push_macro("le32toh") -#pragma push_macro("le64toh") - -#undef MONGO_UINT16_SWAB -#undef MONGO_UINT32_SWAB -#undef MONGO_UINT64_SWAB -#undef htobe16 -#undef htobe32 -#undef htobe64 -#undef htole16 -#undef htole32 -#undef htole64 -#undef be16toh -#undef be32toh -#undef be64toh -#undef le16toh -#undef le32toh -#undef le64toh - -#define MONGO_LITTLE_ENDIAN 1234 -#define MONGO_BIG_ENDIAN 4321 - -#if defined(_MSC_VER) -#include <cstdlib> -#define MONGO_UINT16_SWAB(v) _byteswap_ushort(v) -#define MONGO_UINT32_SWAB(v) _byteswap_ulong(v) -#define MONGO_UINT64_SWAB(v) _byteswap_uint64(v) -#elif defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && \ - (__clang_major__ >= 3) && (__clang_minor__ >= 1) -#if __has_builtin(__builtin_bswap16) -#define MONGO_UINT16_SWAB(v) __builtin_bswap16(v) -#endif -#if __has_builtin(__builtin_bswap32) -#define MONGO_UINT32_SWAB(v) __builtin_bswap32(v) -#endif -#if __has_builtin(__builtin_bswap64) -#define MONGO_UINT64_SWAB(v) __builtin_bswap64(v) -#endif -#elif defined(__GNUC__) && (__GNUC__ >= 4) -#if __GNUC__ >= 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3 -#define MONGO_UINT32_SWAB(v) __builtin_bswap32(v) -#define MONGO_UINT64_SWAB(v) __builtin_bswap64(v) -#endif -#if __GNUC__ >= 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8 -#define MONGO_UINT16_SWAB(v) __builtin_bswap16(v) -#endif -#elif defined(__sun) -#include <sys/byteorder.h> -#define MONGO_UINT16_SWAB(v) BSWAP_16(v) -#define MONGO_UINT32_SWAB(v) BSWAP_32(v) -#define MONGO_UINT64_SWAB(v) BSWAP_64(v) -#endif - -#ifndef MONGO_UINT16_SWAB -#define MONGO_UINT16_SWAB(v) endian::bswap_slow16(v) -#endif - -#ifndef MONGO_UINT32_SWAB -#define MONGO_UINT32_SWAB(v) endian::bswap_slow32(v) -#endif - -#ifndef MONGO_UINT64_SWAB -#define MONGO_UINT64_SWAB(v) endian::bswap_slow64(v) -#endif - -#if MONGO_CONFIG_BYTE_ORDER == MONGO_LITTLE_ENDIAN -#define htobe16(v) MONGO_UINT16_SWAB(v) -#define htobe32(v) MONGO_UINT32_SWAB(v) -#define htobe64(v) MONGO_UINT64_SWAB(v) -#define htole16(v) (v) -#define htole32(v) (v) -#define htole64(v) (v) -#define be16toh(v) MONGO_UINT16_SWAB(v) -#define be32toh(v) MONGO_UINT32_SWAB(v) -#define be64toh(v) MONGO_UINT64_SWAB(v) -#define le16toh(v) (v) -#define le32toh(v) (v) -#define le64toh(v) (v) -#elif MONGO_CONFIG_BYTE_ORDER == MONGO_BIG_ENDIAN -#define htobe16(v) (v) -#define htobe32(v) (v) -#define htobe64(v) (v) -#define htole16(v) MONGO_UINT16_SWAB(v) -#define htole32(v) MONGO_UINT32_SWAB(v) -#define htole64(v) MONGO_UINT64_SWAB(v) -#define be16toh(v) (v) -#define be32toh(v) (v) -#define be64toh(v) (v) -#define le16toh(v) MONGO_UINT16_SWAB(v) -#define le32toh(v) MONGO_UINT32_SWAB(v) -#define le64toh(v) MONGO_UINT64_SWAB(v) +#include <utility> + +namespace mongo::endian { + +/** Like `std::endian`. https://en.cppreference.com/w/cpp/types/endian */ +enum class Order { +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + kLittle, + kBig, + kNative = kLittle, +#elif defined(__GNUC__) + kLittle = __ORDER_LITTLE_ENDIAN__, + kBig = __ORDER_BIG_ENDIAN__, + kNative = __BYTE_ORDER__, #else -#error \ - "The endianness of target architecture is unknown. " \ - "Please define MONGO_CONFIG_BYTE_ORDER" -#endif +#error "Unsupported compiler or architecture" +#endif // compiler check +}; -namespace mongo { -namespace endian { +namespace detail { -static inline uint16_t bswap_slow16(uint16_t v) { - return ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8); +inline std::uint8_t bswap(std::uint8_t v) { + return v; } - -static inline uint32_t bswap_slow32(uint32_t v) { - return ((v & 0x000000FFUL) << 24) | ((v & 0x0000FF00UL) << 8) | ((v & 0x00FF0000UL) >> 8) | - ((v & 0xFF000000UL) >> 24); +#if defined(_MSC_VER) +inline std::uint16_t bswap(std::uint16_t v) { + return _byteswap_ushort(v); +} +inline std::uint32_t bswap(std::uint32_t v) { + return _byteswap_ulong(v); +} +inline std::uint64_t bswap(std::uint64_t v) { + return _byteswap_uint64(v); } +#else // non-MSVC +inline std::uint16_t bswap(std::uint16_t v) { + return __builtin_bswap16(v); +} +inline std::uint32_t bswap(std::uint32_t v) { + return __builtin_bswap32(v); +} +inline std::uint64_t bswap(std::uint64_t v) { + return __builtin_bswap64(v); +} +#endif // non-MSVC -static inline uint64_t bswap_slow64(uint64_t v) { - return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) | - ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) | - ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) | - ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56); +/** + * Same requirements as `std::bit_cast`. `From` is only being trivially copied, but `To` is + * being trivially constructed, which is a stronger operation. + * https://en.cppreference.com/w/cpp/numeric/bit_cast + */ +template <typename To, + typename From, + std::enable_if_t<sizeof(To) == sizeof(From) && // + std::is_trivially_copyable_v<From> && // + std::is_trivial_v<To>, // + int> = 0> +To bitCast(From t) { + To u; + std::memcpy(&u, &t, sizeof(t)); + return u; } template <typename T> -struct ByteOrderConverter; - -template <> -struct ByteOrderConverter<uint8_t> { - typedef uint8_t T; - - inline static T nativeToBig(T t) { - return t; - } - - inline static T bigToNative(T t) { - return t; - } - - inline static T nativeToLittle(T t) { - return t; - } - - inline static T littleToNative(T t) { - return t; - } -}; - -template <> -struct ByteOrderConverter<uint16_t> { - typedef uint16_t T; - - inline static T nativeToBig(T t) { - return htobe16(t); - } - - inline static T bigToNative(T t) { - return be16toh(t); - } - - inline static T nativeToLittle(T t) { - return htole16(t); - } +using RequireArithmetic = std::enable_if_t<std::is_arithmetic_v<T>, int>; - inline static T littleToNative(T t) { - return le16toh(t); - } -}; - -template <> -struct ByteOrderConverter<uint32_t> { - typedef uint32_t T; - - inline static T nativeToBig(T t) { - return htobe32(t); - } - - inline static T bigToNative(T t) { - return be32toh(t); - } - - inline static T nativeToLittle(T t) { - return htole32(t); - } - - inline static T littleToNative(T t) { - return le32toh(t); - } -}; - -template <> -struct ByteOrderConverter<uint64_t> { - typedef uint64_t T; - - inline static T nativeToBig(T t) { - return htobe64(t); - } - - inline static T bigToNative(T t) { - return be64toh(t); - } - - inline static T nativeToLittle(T t) { - return htole64(t); - } - - inline static T littleToNative(T t) { - return le64toh(t); - } -}; +} // namespace detail -template <> -struct ByteOrderConverter<int8_t> { - typedef int8_t T; - - inline static T nativeToBig(T t) { - return t; - } - - inline static T bigToNative(T t) { +template <Order From, Order To, typename T> +T convertByteOrder(T t) { + if constexpr (From == To) { return t; + } else { + static constexpr std::size_t bits = CHAR_BIT * sizeof(T); + // clang-format off + using BitInt = std::conditional_t<bits == 8, std::uint8_t, + std::conditional_t<bits == 16, std::uint16_t, + std::conditional_t<bits == 32, std::uint32_t, + std::conditional_t<bits == 64, std::uint64_t, + void>>>>; + // clang-format on + return detail::bitCast<T>(detail::bswap(detail::bitCast<BitInt>(t))); } - - inline static T nativeToLittle(T t) { - return t; - } - - inline static T littleToNative(T t) { - return t; - } -}; - -template <> -struct ByteOrderConverter<int16_t> { - typedef int16_t T; - - inline static T nativeToBig(T t) { - return htobe16(static_cast<uint16_t>(t)); - } - - inline static T bigToNative(T t) { - return be16toh(static_cast<uint16_t>(t)); - } - - inline static T nativeToLittle(T t) { - return htole16(static_cast<uint16_t>(t)); - } - - inline static T littleToNative(T t) { - return le16toh(static_cast<uint16_t>(t)); - } -}; - -template <> -struct ByteOrderConverter<int32_t> { - typedef int32_t T; - - inline static T nativeToBig(T t) { - return htobe32(static_cast<uint32_t>(t)); - } - - inline static T bigToNative(T t) { - return be32toh(static_cast<uint32_t>(t)); - } - - inline static T nativeToLittle(T t) { - return htole32(static_cast<uint32_t>(t)); - } - - inline static T littleToNative(T t) { - return le32toh(static_cast<uint32_t>(t)); - } -}; - -template <> -struct ByteOrderConverter<int64_t> { - typedef int64_t T; - - inline static T nativeToBig(T t) { - return htobe64(static_cast<uint64_t>(t)); - } - - inline static T bigToNative(T t) { - return be64toh(static_cast<uint64_t>(t)); - } - - inline static T nativeToLittle(T t) { - return htole64(static_cast<uint64_t>(t)); - } - - inline static T littleToNative(T t) { - return le64toh(static_cast<uint64_t>(t)); - } -}; - -template <> -struct ByteOrderConverter<float> { - typedef float T; - - inline static T nativeToBig(T t) { - MONGO_STATIC_ASSERT(sizeof(T) == sizeof(uint32_t)); - - uint32_t temp; - std::memcpy(&temp, &t, sizeof(t)); - temp = htobe32(temp); - std::memcpy(&t, &temp, sizeof(t)); - return t; - } - - inline static T bigToNative(T t) { - uint32_t temp; - std::memcpy(&temp, &t, sizeof(t)); - temp = be32toh(temp); - std::memcpy(&t, &temp, sizeof(t)); - return t; - } - - inline static T nativeToLittle(T t) { - uint32_t temp; - std::memcpy(&temp, &t, sizeof(t)); - temp = htole32(temp); - std::memcpy(&t, &temp, sizeof(t)); - return t; - } - - inline static T littleToNative(T t) { - uint32_t temp; - std::memcpy(&temp, &t, sizeof(t)); - temp = le32toh(temp); - std::memcpy(&t, &temp, sizeof(t)); - return t; - } -}; - -template <> -struct ByteOrderConverter<double> { - typedef double T; - - inline static T nativeToBig(T t) { - MONGO_STATIC_ASSERT(sizeof(T) == sizeof(uint64_t)); - - uint64_t temp; - std::memcpy(&temp, &t, sizeof(t)); - temp = htobe64(temp); - std::memcpy(&t, &temp, sizeof(t)); - return t; - } - - inline static T bigToNative(T t) { - uint64_t temp; - std::memcpy(&temp, &t, sizeof(t)); - temp = be64toh(temp); - std::memcpy(&t, &temp, sizeof(t)); - return t; - } - - inline static T nativeToLittle(T t) { - uint64_t temp; - std::memcpy(&temp, &t, sizeof(t)); - temp = htole64(temp); - std::memcpy(&t, &temp, sizeof(t)); - return t; - } - - inline static T littleToNative(T t) { - uint64_t temp; - std::memcpy(&temp, &t, sizeof(t)); - temp = le64toh(temp); - std::memcpy(&t, &temp, sizeof(t)); - return t; - } -}; - -template <> -struct ByteOrderConverter<Decimal128::Value> { - typedef Decimal128::Value T; - - inline static T nativeToBig(T t) { - t.low64 = ByteOrderConverter<uint64_t>::nativeToBig(t.low64); - t.high64 = ByteOrderConverter<uint64_t>::nativeToBig(t.high64); - return t; - } - - inline static T bigToNative(T t) { - t.low64 = ByteOrderConverter<uint64_t>::bigToNative(t.low64); - t.high64 = ByteOrderConverter<uint64_t>::bigToNative(t.high64); - return t; - } - - inline static T nativeToLittle(T t) { - t.low64 = ByteOrderConverter<uint64_t>::nativeToLittle(t.low64); - t.high64 = ByteOrderConverter<uint64_t>::nativeToLittle(t.high64); - return t; - } - - inline static T littleToNative(T t) { - t.low64 = ByteOrderConverter<uint64_t>::littleToNative(t.low64); - t.high64 = ByteOrderConverter<uint64_t>::littleToNative(t.high64); - return t; - } -}; - -// Use a typemape to normalize non-fixed-width integral types to the associated fixed width -// types. - -template <typename T> -struct IntegralTypeMap { - typedef T type; -}; - -template <> -struct IntegralTypeMap<signed char> { - MONGO_STATIC_ASSERT(CHAR_BIT == 8); - typedef int8_t type; -}; - -template <> -struct IntegralTypeMap<unsigned char> { - MONGO_STATIC_ASSERT(CHAR_BIT == 8); - typedef uint8_t type; -}; - -template <> -struct IntegralTypeMap<char> { - MONGO_STATIC_ASSERT(CHAR_BIT == 8); - typedef std::conditional<std::is_signed<char>::value, int8_t, uint8_t>::type type; -}; - -template <> -struct IntegralTypeMap<long long> { - MONGO_STATIC_ASSERT(sizeof(long long) == sizeof(int64_t)); - typedef int64_t type; -}; - -template <> -struct IntegralTypeMap<unsigned long long> { - MONGO_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t)); - typedef uint64_t type; -}; - -template <typename T> -inline T nativeToBig(T t) { - return ByteOrderConverter<typename IntegralTypeMap<T>::type>::nativeToBig(t); } -template <typename T> -inline T bigToNative(T t) { - return ByteOrderConverter<typename IntegralTypeMap<T>::type>::bigToNative(t); +template <typename T, detail::RequireArithmetic<T> = 0> +T nativeToBig(T t) { + return convertByteOrder<Order::kNative, Order::kBig>(t); } -template <typename T> -inline T nativeToLittle(T t) { - return ByteOrderConverter<typename IntegralTypeMap<T>::type>::nativeToLittle(t); +template <typename T, detail::RequireArithmetic<T> = 0> +T nativeToLittle(T t) { + return convertByteOrder<Order::kNative, Order::kLittle>(t); } -template <typename T> -inline T littleToNative(T t) { - return ByteOrderConverter<typename IntegralTypeMap<T>::type>::littleToNative(t); +template <typename T, detail::RequireArithmetic<T> = 0> +T bigToNative(T t) { + return convertByteOrder<Order::kBig, Order::kNative>(t); } -} // namespace endian -} // namespace mongo - -#undef MONGO_UINT16_SWAB -#undef MONGO_UINT32_SWAB -#undef MONGO_UINT64_SWAB -#undef htobe16 -#undef htobe32 -#undef htobe64 -#undef htole16 -#undef htole32 -#undef htole64 -#undef be16toh -#undef be32toh -#undef be64toh -#undef le16toh -#undef le32toh -#undef le64toh +template <typename T, detail::RequireArithmetic<T> = 0> +T littleToNative(T t) { + return convertByteOrder<Order::kLittle, Order::kNative>(t); +} -#pragma pop_macro("MONGO_UINT16_SWAB") -#pragma pop_macro("MONGO_UINT32_SWAB") -#pragma pop_macro("MONGO_UINT64_SWAB") -#pragma pop_macro("htobe16") -#pragma pop_macro("htobe32") -#pragma pop_macro("htobe64") -#pragma pop_macro("htole16") -#pragma pop_macro("htole32") -#pragma pop_macro("htole64") -#pragma pop_macro("be16toh") -#pragma pop_macro("be32toh") -#pragma pop_macro("be64toh") -#pragma pop_macro("le16toh") -#pragma pop_macro("le32toh") -#pragma pop_macro("le64toh") +} // namespace mongo::endian |