/* * Copyright (c) 2020, the SerenityOS developers. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include 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 __builtin_bswap64(value); if constexpr (sizeof(T) == 4) return __builtin_bswap32(value); if constexpr (sizeof(T) == 2) return __builtin_bswap16(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 __builtin_bswap64(value); if constexpr (sizeof(T) == 4) return __builtin_bswap32(value); if constexpr (sizeof(T) == 2) return __builtin_bswap16(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 LittleEndian; template InputStream& operator>>(InputStream&, LittleEndian&); template OutputStream& operator<<(OutputStream&, LittleEndian); template class [[gnu::packed]] LittleEndian { public: friend InputStream& operator>>(InputStream&, LittleEndian&); friend OutputStream& operator<<(OutputStream&, LittleEndian); constexpr LittleEndian() { } 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 BigEndian; template InputStream& operator>>(InputStream&, BigEndian&); template OutputStream& operator<<(OutputStream&, BigEndian); template class [[gnu::packed]] BigEndian { public: friend InputStream& operator>>(InputStream&, BigEndian&); friend OutputStream& operator<<(OutputStream&, BigEndian); 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; } using AK::BigEndian; using AK::LittleEndian; using AK::NetworkOrdered;