wut/tools/common/utils.h

168 lines
4.3 KiB
C
Raw Normal View History

2016-01-04 13:17:43 +00:00
#pragma once
2018-05-29 09:01:28 +01:00
#include <algorithm>
2018-06-13 18:48:35 +01:00
#include <cctype>
2018-05-23 11:10:23 +01:00
#include <cstdint>
2016-01-04 13:17:43 +00:00
#include <cstring>
2018-05-29 09:01:28 +01:00
#include <string>
2016-01-04 13:17:43 +00:00
#include <type_traits>
#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 <byteswap.h>
#endif
// reinterpret_cast for value types
template<typename DstType, typename SrcType>
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<SrcType>::value, "SrcType is not trivially copyable.");
static_assert(std::is_trivially_copyable<DstType>::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<typename Type, unsigned Size = sizeof(Type)>
struct byte_swap_t;
template<typename Type>
struct byte_swap_t<Type, 1>
{
static Type swap(Type src)
{
return src;
}
};
template<typename Type>
struct byte_swap_t<Type, 2>
{
static Type swap(Type src)
{
#ifdef PLATFORM_WINDOWS
return bit_cast<Type>(_byteswap_ushort(bit_cast<uint16_t>(src)));
#elif defined(PLATFORM_LINUX)
return bit_cast<Type>(bswap_16(bit_cast<uint16_t>(src)));
#else
const uint16_t data = bit_cast<uint16_t>(src);
return bit_cast<Type>(static_cast<uint16_t>((data >> 8) | (data << 8)));
2016-01-04 13:17:43 +00:00
#endif
}
};
template<typename Type>
struct byte_swap_t<Type, 4>
{
static Type swap(Type src)
{
#ifdef PLATFORM_WINDOWS
return bit_cast<Type>(_byteswap_ulong(bit_cast<uint32_t>(src)));
#elif defined(PLATFORM_APPLE)
return bit_cast<Type>(__builtin_bswap32(bit_cast<uint32_t>(src)));
#elif defined(PLATFORM_LINUX)
return bit_cast<Type>(bswap_32(bit_cast<uint32_t>(src)));
#else
const uint32_t data = bit_cast<uint32_t>(src);
return bit_cast<Type>(
((data & 0xFF000000u) >> 24) |
((data & 0x00FF0000u) >> 8) |
((data & 0x0000FF00u) << 8) |
((data & 0x000000FFu) << 24)
);
2016-01-04 13:17:43 +00:00
#endif
}
};
template<typename Type>
struct byte_swap_t<Type, 8>
{
static Type swap(Type src)
{
#ifdef PLATFORM_WINDOWS
return bit_cast<Type>(_byteswap_uint64(bit_cast<uint64_t>(src)));
#elif defined(PLATFORM_APPLE)
return bit_cast<Type>(__builtin_bswap64(bit_cast<uint64_t>(src)));
#elif defined(PLATFORM_LINUX)
return bit_cast<Type>(bswap_64(bit_cast<uint64_t>(src)));
#else
uint64_t data = bit_cast<uint64_t>(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<Type>(data);
2016-01-04 13:17:43 +00:00
#endif
}
};
// Swaps endian of src
template<typename Type>
inline Type
byte_swap(Type src)
{
return byte_swap_t<Type>::swap(src);
}
// Alignment helpers
template<typename Type>
constexpr inline Type
align_up(Type value, size_t alignment)
{
return static_cast<Type>((static_cast<size_t>(value) + (alignment - 1)) & ~(alignment - 1));
}
template<typename Type>
constexpr inline Type
align_down(Type value, size_t alignment)
{
return static_cast<Type>(static_cast<size_t>(value) & ~(alignment - 1));
}
2018-05-24 23:32:08 +01:00
template<typename Type>
constexpr bool
align_check(Type value, size_t alignment)
{
return (static_cast<size_t>(value) & (alignment - 1)) == 0;
}
2016-01-04 13:17:43 +00:00
#define CHECK_SIZE(Type, Size) \
static_assert(sizeof(Type) == Size, \
#Type " must be " #Size " bytes")
2018-05-29 09:01:28 +01:00
// 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));
}