#pragma once #include #include #include #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_LINUX) return bit_cast(bswap_16(bit_cast(src))); #else const uint16_t data = bit_cast(src); return bit_cast(static_cast((data >> 8) | (data << 8))); #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))); #else const uint32_t data = bit_cast(src); return bit_cast( ((data & 0xFF000000u) >> 24) | ((data & 0x00FF0000u) >> 8) | ((data & 0x0000FF00u) << 8) | ((data & 0x000000FFu) << 24) ); #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))); #else uint64_t data = bit_cast(src); data = ((data & 0x00000000FFFFFFFFull) << 32) | ((data & 0xFFFFFFFF00000000ull) >> 32); data = ((data & 0x0000FFFF0000FFFFull) << 16) | ((data & 0xFFFF0000FFFF0000ull) >> 16); data = ((data & 0x00FF00FF00FF00FFull) << 8) | ((data & 0xFF00FF00FF00FF00ull) >> 8); return bit_cast(data); #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") // trim from start // Taken from https://stackoverflow.com/a/217605 static inline std::string ltrim(std::string s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); return s; } // trim from end (in place) static inline std::string rtrim(std::string s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); return s; } // trim from both ends static inline std::string trim(std::string s) { return rtrim(ltrim(s)); }