#pragma once #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)); } #define CHECK_SIZE(Type, Size) \ static_assert(sizeof(Type) == Size, \ #Type " must be " #Size " bytes")