/* * Copyright (c) 2020, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #if defined(AK_OS_MACOS) # include # include # define htobe16(x) OSSwapHostToBigInt16(x) # define htole16(x) OSSwapHostToLittleInt16(x) # define be16toh(x) OSSwapBigToHostInt16(x) # define le16toh(x) OSSwapLittleToHostInt16(x) # define htobe32(x) OSSwapHostToBigInt32(x) # define htole32(x) OSSwapHostToLittleInt32(x) # define be32toh(x) OSSwapBigToHostInt32(x) # define le32toh(x) OSSwapLittleToHostInt32(x) # define htobe64(x) OSSwapHostToBigInt64(x) # define htole64(x) OSSwapHostToLittleInt64(x) # define be64toh(x) OSSwapBigToHostInt64(x) # define le64toh(x) OSSwapLittleToHostInt64(x) # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # define __BYTE_ORDER BYTE_ORDER #endif namespace AK { template ALWAYS_INLINE constexpr T convert_between_host_and_little_endian(T value) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ return value; #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ if constexpr (sizeof(T) == 8) return static_cast(__builtin_bswap64(static_cast(value))); if constexpr (sizeof(T) == 4) return static_cast(__builtin_bswap32(static_cast(value))); if constexpr (sizeof(T) == 2) return static_cast(__builtin_bswap16(static_cast(value))); if constexpr (sizeof(T) == 1) return value; #endif } template ALWAYS_INLINE constexpr T convert_between_host_and_big_endian(T value) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ if constexpr (sizeof(T) == 8) return static_cast(__builtin_bswap64(static_cast(value))); if constexpr (sizeof(T) == 4) return static_cast(__builtin_bswap32(static_cast(value))); if constexpr (sizeof(T) == 2) return static_cast(__builtin_bswap16(static_cast(value))); if constexpr (sizeof(T) == 1) return value; #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ return value; #endif } template ALWAYS_INLINE T convert_between_host_and_network_endian(T value) { return convert_between_host_and_big_endian(value); } template class [[gnu::packed]] LittleEndian { public: constexpr LittleEndian() = default; constexpr LittleEndian(T value) : m_value(convert_between_host_and_little_endian(value)) { } constexpr operator T() const { return convert_between_host_and_little_endian(m_value); } private: T m_value { 0 }; }; template class [[gnu::packed]] BigEndian { public: constexpr BigEndian() = default; constexpr BigEndian(T value) : m_value(convert_between_host_and_big_endian(value)) { } constexpr operator T() const { return convert_between_host_and_big_endian(m_value); } private: T m_value { 0 }; }; template using NetworkOrdered = BigEndian; template requires(HasFormatter) struct Formatter> : Formatter { }; template requires(HasFormatter) struct Formatter> : Formatter { }; template struct Traits> : public GenericTraits> { static constexpr bool is_trivially_serializable() { return Traits::is_trivially_serializable(); } }; template struct Traits> : public GenericTraits> { static constexpr bool is_trivially_serializable() { return Traits::is_trivially_serializable(); } }; } #if USING_AK_GLOBALLY using AK::BigEndian; using AK::LittleEndian; using AK::NetworkOrdered; #endif