276 lines
10 KiB
C
276 lines
10 KiB
C
|
// File: crn_utils.h
|
||
|
// See Copyright Notice and license at the end of inc/crnlib.h
|
||
|
#pragma once
|
||
|
|
||
|
#define CRNLIB_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||
|
#define CRNLIB_MAX(a, b) (((a) < (b)) ? (b) : (a))
|
||
|
|
||
|
#define CRNLIB_ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
// Need to explictly extern these with MSVC, but not MinGW.
|
||
|
extern "C" unsigned long __cdecl _lrotl(unsigned long, int);
|
||
|
#pragma intrinsic(_lrotl)
|
||
|
|
||
|
extern "C" unsigned long __cdecl _lrotr(unsigned long, int);
|
||
|
#pragma intrinsic(_lrotr)
|
||
|
#endif
|
||
|
|
||
|
#ifdef WIN32
|
||
|
#define CRNLIB_ROTATE_LEFT(x, k) _lrotl(x, k)
|
||
|
#define CRNLIB_ROTATE_RIGHT(x, k) _lrotr(x, k)
|
||
|
#else
|
||
|
#define CRNLIB_ROTATE_LEFT(x, k) (((x) << (k)) | ((x) >> (32-(k))))
|
||
|
#define CRNLIB_ROTATE_RIGHT(x, k) (((x) >> (k)) | ((x) << (32-(k))))
|
||
|
#endif
|
||
|
|
||
|
template<class T, size_t N> T decay_array_to_subtype(T (&a)[N]);
|
||
|
#define CRNLIB_ARRAY_SIZE(X) (sizeof(X) / sizeof(decay_array_to_subtype(X)))
|
||
|
|
||
|
#define CRNLIB_SIZEOF_U32(x) static_cast<uint32>(sizeof(x))
|
||
|
|
||
|
namespace crnlib
|
||
|
{
|
||
|
namespace utils
|
||
|
{
|
||
|
template<typename T> inline void swap(T& l, T& r)
|
||
|
{
|
||
|
T temp(l);
|
||
|
l = r;
|
||
|
r = temp;
|
||
|
}
|
||
|
|
||
|
template<typename T> inline void zero_object(T& obj)
|
||
|
{
|
||
|
memset((void*)&obj, 0, sizeof(obj));
|
||
|
}
|
||
|
|
||
|
template<typename T> inline void zero_this(T* pObj)
|
||
|
{
|
||
|
memset((void*)pObj, 0, sizeof(*pObj));
|
||
|
}
|
||
|
|
||
|
inline bool is_bit_set(uint bits, uint mask)
|
||
|
{
|
||
|
return (bits & mask) != 0;
|
||
|
}
|
||
|
|
||
|
inline void set_bit(uint& bits, uint mask, bool state)
|
||
|
{
|
||
|
if (state)
|
||
|
bits |= mask;
|
||
|
else
|
||
|
bits &= ~mask;
|
||
|
}
|
||
|
|
||
|
inline bool is_flag_set(uint bits, uint flag)
|
||
|
{
|
||
|
CRNLIB_ASSERT(flag < 32U);
|
||
|
return is_bit_set(bits, 1U << flag);
|
||
|
}
|
||
|
|
||
|
inline void set_flag(uint& bits, uint flag, bool state)
|
||
|
{
|
||
|
CRNLIB_ASSERT(flag < 32U);
|
||
|
set_bit(bits, 1U << flag, state);
|
||
|
}
|
||
|
|
||
|
inline void invert_buf(void* pBuf, uint size)
|
||
|
{
|
||
|
uint8* p = static_cast<uint8*>(pBuf);
|
||
|
|
||
|
const uint half_size = size >> 1;
|
||
|
for (uint i = 0; i < half_size; i++)
|
||
|
utils::swap(p[i], p[size - 1U - i]);
|
||
|
}
|
||
|
|
||
|
// buffer_is_little_endian is the endianness of the buffer's data
|
||
|
template<typename T>
|
||
|
inline void write_obj(const T& obj, void* pBuf, bool buffer_is_little_endian)
|
||
|
{
|
||
|
const uint8* pSrc = reinterpret_cast<const uint8*>(&obj);
|
||
|
uint8* pDst = static_cast<uint8*>(pBuf);
|
||
|
|
||
|
if (c_crnlib_little_endian_platform == buffer_is_little_endian)
|
||
|
memcpy(pDst, pSrc, sizeof(T));
|
||
|
else
|
||
|
{
|
||
|
for (uint i = 0; i < sizeof(T); i++)
|
||
|
pDst[i] = pSrc[sizeof(T) - 1 - i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// buffer_is_little_endian is the endianness of the buffer's data
|
||
|
template<typename T>
|
||
|
inline void read_obj(T& obj, const void* pBuf, bool buffer_is_little_endian)
|
||
|
{
|
||
|
const uint8* pSrc = reinterpret_cast<const uint8*>(pBuf);
|
||
|
uint8* pDst = reinterpret_cast<uint8*>(&obj);
|
||
|
|
||
|
if (c_crnlib_little_endian_platform == buffer_is_little_endian)
|
||
|
memcpy(pDst, pSrc, sizeof(T));
|
||
|
else
|
||
|
{
|
||
|
for (uint i = 0; i < sizeof(T); i++)
|
||
|
pDst[i] = pSrc[sizeof(T) - 1 - i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<typename T>
|
||
|
inline bool write_obj(const T& obj, void*& pBuf, uint& buf_size, bool buffer_is_little_endian)
|
||
|
{
|
||
|
if (buf_size < sizeof(T))
|
||
|
return false;
|
||
|
|
||
|
utils::write_obj(obj, pBuf, buffer_is_little_endian);
|
||
|
|
||
|
pBuf = static_cast<uint8*>(pBuf) + sizeof(T);
|
||
|
buf_size -= sizeof(T);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
inline bool write_val(uint8 val, void*& pBuf, uint& buf_size, bool buffer_is_little_endian) { return write_obj(val, pBuf, buf_size, buffer_is_little_endian); }
|
||
|
inline bool write_val(uint16 val, void*& pBuf, uint& buf_size, bool buffer_is_little_endian) { return write_obj(val, pBuf, buf_size, buffer_is_little_endian); }
|
||
|
inline bool write_val(uint val, void*& pBuf, uint& buf_size, bool buffer_is_little_endian) { return write_obj(val, pBuf, buf_size, buffer_is_little_endian); }
|
||
|
inline bool write_val(int val, void*& pBuf, uint& buf_size, bool buffer_is_little_endian) { return write_obj(val, pBuf, buf_size, buffer_is_little_endian); }
|
||
|
inline bool write_val(uint64 val, void*& pBuf, uint& buf_size, bool buffer_is_little_endian) { return write_obj(val, pBuf, buf_size, buffer_is_little_endian); }
|
||
|
inline bool write_val(float val, void*& pBuf, uint& buf_size, bool buffer_is_little_endian) { return write_obj(val, pBuf, buf_size, buffer_is_little_endian); }
|
||
|
inline bool write_val(double val, void*& pBuf, uint& buf_size, bool buffer_is_little_endian) { return write_obj(val, pBuf, buf_size, buffer_is_little_endian); }
|
||
|
|
||
|
template<typename T>
|
||
|
inline bool read_obj(T& obj, const void*& pBuf, uint& buf_size, bool buffer_is_little_endian)
|
||
|
{
|
||
|
if (buf_size < sizeof(T))
|
||
|
{
|
||
|
zero_object(obj);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
utils::read_obj(obj, pBuf, buffer_is_little_endian);
|
||
|
|
||
|
pBuf = static_cast<const uint8*>(pBuf) + sizeof(T);
|
||
|
buf_size -= sizeof(T);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#if defined(_MSC_VER)
|
||
|
static CRNLIB_FORCE_INLINE uint16 swap16(uint16 x) { return _byteswap_ushort(x); }
|
||
|
static CRNLIB_FORCE_INLINE uint32 swap32(uint32 x) { return _byteswap_ulong(x); }
|
||
|
static CRNLIB_FORCE_INLINE uint64 swap64(uint64 x) { return _byteswap_uint64(x); }
|
||
|
#elif defined(__GNUC__)
|
||
|
static CRNLIB_FORCE_INLINE uint16 swap16(uint16 x) { return static_cast<uint16>((x << 8U) | (x >> 8U)); }
|
||
|
static CRNLIB_FORCE_INLINE uint32 swap32(uint32 x) { return __builtin_bswap32(x); }
|
||
|
static CRNLIB_FORCE_INLINE uint64 swap64(uint64 x) { return __builtin_bswap64(x); }
|
||
|
#else
|
||
|
static CRNLIB_FORCE_INLINE uint16 swap16(uint16 x) { return static_cast<uint16>((x << 8U) | (x >> 8U)); }
|
||
|
static CRNLIB_FORCE_INLINE uint32 swap32(uint32 x) { return ((x << 24U) | ((x << 8U) & 0x00FF0000U) | ((x >> 8U) & 0x0000FF00U) | (x >> 24U)); }
|
||
|
static CRNLIB_FORCE_INLINE uint64 swap64(uint64 x) { return (static_cast<uint64>(swap32(static_cast<uint32>(x))) << 32ULL) | swap32(static_cast<uint32>(x >> 32U)); }
|
||
|
#endif
|
||
|
|
||
|
// Assumes x has been read from memory as a little endian value, converts to native endianness for manipulation.
|
||
|
CRNLIB_FORCE_INLINE uint16 swap_le16_to_native(uint16 x) { return c_crnlib_little_endian_platform ? x : swap16(x); }
|
||
|
CRNLIB_FORCE_INLINE uint32 swap_le32_to_native(uint32 x) { return c_crnlib_little_endian_platform ? x : swap32(x); }
|
||
|
CRNLIB_FORCE_INLINE uint64 swap_le64_to_native(uint64 x) { return c_crnlib_little_endian_platform ? x : swap64(x); }
|
||
|
|
||
|
// Assumes x has been read from memory as a big endian value, converts to native endianness for manipulation.
|
||
|
CRNLIB_FORCE_INLINE uint16 swap_be16_to_native(uint16 x) { return c_crnlib_big_endian_platform ? x : swap16(x); }
|
||
|
CRNLIB_FORCE_INLINE uint32 swap_be32_to_native(uint32 x) { return c_crnlib_big_endian_platform ? x : swap32(x); }
|
||
|
CRNLIB_FORCE_INLINE uint64 swap_be64_to_native(uint64 x) { return c_crnlib_big_endian_platform ? x : swap64(x); }
|
||
|
|
||
|
CRNLIB_FORCE_INLINE uint32 read_le32(const void* p) { return swap_le32_to_native(*static_cast<const uint32*>(p)); }
|
||
|
CRNLIB_FORCE_INLINE void write_le32(void* p, uint32 x) { *static_cast<uint32*>(p) = swap_le32_to_native(x); }
|
||
|
CRNLIB_FORCE_INLINE uint64 read_le64(const void* p) { return swap_le64_to_native(*static_cast<const uint64*>(p)); }
|
||
|
CRNLIB_FORCE_INLINE void write_le64(void* p, uint64 x) { *static_cast<uint64*>(p) = swap_le64_to_native(x); }
|
||
|
|
||
|
CRNLIB_FORCE_INLINE uint32 read_be32(const void* p) { return swap_be32_to_native(*static_cast<const uint32*>(p)); }
|
||
|
CRNLIB_FORCE_INLINE void write_be32(void* p, uint32 x) { *static_cast<uint32*>(p) = swap_be32_to_native(x); }
|
||
|
CRNLIB_FORCE_INLINE uint64 read_be64(const void* p) { return swap_be64_to_native(*static_cast<const uint64*>(p)); }
|
||
|
CRNLIB_FORCE_INLINE void write_be64(void* p, uint64 x) { *static_cast<uint64*>(p) = swap_be64_to_native(x); }
|
||
|
|
||
|
inline void endian_swap_mem16(uint16* p, uint n) { while (n--) { *p = swap16(*p); ++p; } }
|
||
|
inline void endian_swap_mem32(uint32* p, uint n) { while (n--) { *p = swap32(*p); ++p; } }
|
||
|
inline void endian_swap_mem64(uint64* p, uint n) { while (n--) { *p = swap64(*p); ++p; } }
|
||
|
|
||
|
inline void endian_swap_mem(void* p, uint size_in_bytes, uint type_size)
|
||
|
{
|
||
|
switch (type_size)
|
||
|
{
|
||
|
case sizeof(uint16): endian_swap_mem16(static_cast<uint16*>(p), size_in_bytes / type_size); break;
|
||
|
case sizeof(uint32): endian_swap_mem32(static_cast<uint32*>(p), size_in_bytes / type_size); break;
|
||
|
case sizeof(uint64): endian_swap_mem64(static_cast<uint64*>(p), size_in_bytes / type_size); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void fast_memset(void* pDst, int val, size_t size)
|
||
|
{
|
||
|
memset(pDst, val, size);
|
||
|
}
|
||
|
|
||
|
inline void fast_memcpy(void* pDst, const void* pSrc, size_t size)
|
||
|
{
|
||
|
memcpy(pDst, pSrc, size);
|
||
|
}
|
||
|
|
||
|
inline uint count_leading_zeros(uint v)
|
||
|
{
|
||
|
uint temp;
|
||
|
uint n = 32;
|
||
|
|
||
|
temp = v >> 16;
|
||
|
if (temp) { n -= 16; v = temp; }
|
||
|
|
||
|
temp = v >> 8;
|
||
|
if (temp) { n -= 8; v = temp; }
|
||
|
|
||
|
temp = v >> 4;
|
||
|
if (temp) { n -= 4; v = temp; }
|
||
|
|
||
|
temp = v >> 2;
|
||
|
if (temp) { n -= 2; v = temp; }
|
||
|
|
||
|
temp = v >> 1;
|
||
|
if (temp) { n -= 1; v = temp; }
|
||
|
|
||
|
if (v & 1) n--;
|
||
|
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
inline uint count_leading_zeros16(uint v)
|
||
|
{
|
||
|
CRNLIB_ASSERT(v < 0x10000);
|
||
|
|
||
|
uint temp;
|
||
|
uint n = 16;
|
||
|
|
||
|
temp = v >> 8;
|
||
|
if (temp) { n -= 8; v = temp; }
|
||
|
|
||
|
temp = v >> 4;
|
||
|
if (temp) { n -= 4; v = temp; }
|
||
|
|
||
|
temp = v >> 2;
|
||
|
if (temp) { n -= 2; v = temp; }
|
||
|
|
||
|
temp = v >> 1;
|
||
|
if (temp) { n -= 1; v = temp; }
|
||
|
|
||
|
if (v & 1) n--;
|
||
|
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
void endian_switch_words(uint16* p, uint num);
|
||
|
void endian_switch_dwords(uint32* p, uint num);
|
||
|
void copy_words(uint16* pDst, const uint16* pSrc, uint num, bool endian_switch);
|
||
|
void copy_dwords(uint32* pDst, const uint32* pSrc, uint num, bool endian_switch);
|
||
|
|
||
|
uint compute_max_mips(uint width, uint height);
|
||
|
|
||
|
} // namespace utils
|
||
|
|
||
|
} // namespace crnlib
|
||
|
|