#pragma once #include #include #include #if defined(WIN32) || defined(_WIN32) || defined(_MSC_VER) #define PLATFORM_WINDOWS #elif __APPLE__ #define PLATFORM_APPLE #define PLATFORM_POSIX #elif __linux__ #define PLATFORM_LINUX #define PLATFORM_POSIX #endif #ifdef PLATFORM_LINUX #include #endif // reinterpret_cast for value types template inline DstType bit_cast(const SrcType& src) { static_assert(sizeof(SrcType) == sizeof(DstType), "bit_cast must be between same sized types"); static_assert(std::is_trivially_copyable::value, "SrcType is not trivially copyable."); static_assert(std::is_trivially_copyable::value, "DstType is not trivially copyable."); DstType dst; std::memcpy(&dst, &src, sizeof(SrcType)); return dst; } // Utility class to swap endian for types of size 1, 2, 4, 8 // other type sizes are not supported template struct byte_swap_t; template struct byte_swap_t { static Type swap(Type src) { return src; } }; template struct byte_swap_t { static Type swap(Type src) { #ifdef PLATFORM_WINDOWS return bit_cast(_byteswap_ushort(bit_cast(src))); #elif defined(PLATFORM_APPLE) // Apple has no 16-bit byteswap intrinsic const uint16_t data = bit_cast(src); return bit_cast((uint16_t)((data >> 8) | (data << 8))); #elif defined(PLATFORM_LINUX) return bit_cast(bswap_16(bit_cast(src))); #endif } }; template struct byte_swap_t { static Type swap(Type src) { #ifdef PLATFORM_WINDOWS return bit_cast(_byteswap_ulong(bit_cast(src))); #elif defined(PLATFORM_APPLE) return bit_cast(__builtin_bswap32(bit_cast(src))); #elif defined(PLATFORM_LINUX) return bit_cast(bswap_32(bit_cast(src))); #endif } }; template struct byte_swap_t { static Type swap(Type src) { #ifdef PLATFORM_WINDOWS return bit_cast(_byteswap_uint64(bit_cast(src))); #elif defined(PLATFORM_APPLE) return bit_cast(__builtin_bswap64(bit_cast(src))); #elif defined(PLATFORM_LINUX) return bit_cast(bswap_64(bit_cast(src))); #endif } }; // Swaps endian of src template inline Type byte_swap(Type src) { return byte_swap_t::swap(src); } // Alignment helpers template constexpr inline Type align_up(Type value, size_t alignment) { return static_cast((static_cast(value) + (alignment - 1)) & ~(alignment - 1)); } template constexpr inline Type align_down(Type value, size_t alignment) { return static_cast(static_cast(value) & ~(alignment - 1)); } template constexpr bool align_check(Type value, size_t alignment) { return (static_cast(value) & (alignment - 1)) == 0; } #define CHECK_SIZE(Type, Size) \ static_assert(sizeof(Type) == Size, \ #Type " must be " #Size " bytes")