/* * Copyright (c) 2020, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include namespace AK { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ inline constexpr static bool HostIsLittleEndian = true; #else inline constexpr static bool HostIsLittleEndian = false; #endif template ALWAYS_INLINE constexpr T convert_between_host_and_little_endian(T value) { if constexpr (HostIsLittleEndian || sizeof(T) == 1) return value; else if constexpr (sizeof(T) == 8) return static_cast(__builtin_bswap64(static_cast(value))); else if constexpr (sizeof(T) == 4) return static_cast(__builtin_bswap32(static_cast(value))); else if constexpr (sizeof(T) == 2) return static_cast(__builtin_bswap16(static_cast(value))); else static_assert(DependentFalse, "Cannot byte-swap values larger than 64-bits"); } template ALWAYS_INLINE constexpr T convert_between_host_and_big_endian(T value) { if constexpr (sizeof(T) == 1 || !HostIsLittleEndian) return value; else if constexpr (sizeof(T) == 8) return static_cast(__builtin_bswap64(static_cast(value))); else if constexpr (sizeof(T) == 4) return static_cast(__builtin_bswap32(static_cast(value))); else if constexpr (sizeof(T) == 2) return static_cast(__builtin_bswap16(static_cast(value))); else static_assert(DependentFalse, "Cannot byte-swap values larger than 64-bits"); } 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 DefaultTraits> { static constexpr bool is_trivially_serializable() { return Traits::is_trivially_serializable(); } }; template struct Traits> : public DefaultTraits> { static constexpr bool is_trivially_serializable() { return Traits::is_trivially_serializable(); } }; constexpr u16 bitswap(u16 v) { v = ((v >> 1) & 0x5555) | ((v & 0x5555) << 1); // even & odd bits v = ((v >> 2) & 0x3333) | ((v & 0x3333) << 2); // pairs v = ((v >> 4) & 0x0F0F) | ((v & 0x0F0F) << 4); // nibbles return ((v >> 8) & 0x00FF) | ((v & 0x00FF) << 8); // bytes } } #if USING_AK_GLOBALLY using AK::BigEndian; using AK::bitswap; using AK::LittleEndian; using AK::NetworkOrdered; #endif