summaryrefslogtreecommitdiff
path: root/src/mongo/platform/endian.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/platform/endian.h')
-rw-r--r--src/mongo/platform/endian.h567
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