// 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 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(sizeof(x)) namespace crnlib { namespace utils { template inline void swap(T& l, T& r) { T temp(l); l = r; r = temp; } template inline void zero_object(T& obj) { memset((void*)&obj, 0, sizeof(obj)); } template 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(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 inline void write_obj(const T& obj, void* pBuf, bool buffer_is_little_endian) { const uint8* pSrc = reinterpret_cast(&obj); uint8* pDst = static_cast(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 inline void read_obj(T& obj, const void* pBuf, bool buffer_is_little_endian) { const uint8* pSrc = reinterpret_cast(pBuf); uint8* pDst = reinterpret_cast(&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 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(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 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(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((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((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(swap32(static_cast(x))) << 32ULL) | swap32(static_cast(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(p)); } CRNLIB_FORCE_INLINE void write_le32(void* p, uint32 x) { *static_cast(p) = swap_le32_to_native(x); } CRNLIB_FORCE_INLINE uint64 read_le64(const void* p) { return swap_le64_to_native(*static_cast(p)); } CRNLIB_FORCE_INLINE void write_le64(void* p, uint64 x) { *static_cast(p) = swap_le64_to_native(x); } CRNLIB_FORCE_INLINE uint32 read_be32(const void* p) { return swap_be32_to_native(*static_cast(p)); } CRNLIB_FORCE_INLINE void write_be32(void* p, uint32 x) { *static_cast(p) = swap_be32_to_native(x); } CRNLIB_FORCE_INLINE uint64 read_be64(const void* p) { return swap_be64_to_native(*static_cast(p)); } CRNLIB_FORCE_INLINE void write_be64(void* p, uint64 x) { *static_cast(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(p), size_in_bytes / type_size); break; case sizeof(uint32): endian_swap_mem32(static_cast(p), size_in_bytes / type_size); break; case sizeof(uint64): endian_swap_mem64(static_cast(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