#ifndef NW4R_UT_ALGORITHM_H #define NW4R_UT_ALGORITHM_H #include namespace nw4r { namespace ut { namespace { /** * Value operations */ template inline T Max(T t1, T t2) { return (t1 < t2) ? t2 : t1; } template inline T Min(T t1, T t2) { return (t1 > t2) ? t2 : t1; } template inline T Clamp(T value, T min, T max) { return value > max ? max : (value < min ? min : value); } template inline T Abs(T x) { // Static cast needed to break abs optimization during instruction selection return x < 0 ? static_cast(-x) : static_cast(x); } template <> f32 inline Abs(register f32 x) { register f32 ax; // clang-format off asm { fabs ax, x } // clang-format on return ax; } /** * Bit operations */ template inline T BitExtract(T bits, int pos, int len) { T mask = (1 << len) - 1; return (bits >> pos) & mask; } template inline bool TestBit(T t, int bitIndexLSB) { return BitExtract(t, sizeof(T), bitIndexLSB); } /** * Pointer operations */ inline u32 GetIntPtr(const void *ptr) { return reinterpret_cast(ptr); } template inline const void *AddOffsetToPtr(const void *ptr, T offset) { return reinterpret_cast(GetIntPtr(ptr) + offset); } inline s32 GetOffsetFromPtr(const void *start, const void *end) { return static_cast(GetIntPtr(end) - GetIntPtr(start)); } inline int ComparePtr(const void *p1, const void *p2) { return static_cast(GetIntPtr(p1) - GetIntPtr(p2)); } /** * Rounding */ template inline T RoundUp(T t, unsigned int alignment) { return (alignment + t - 1) & ~(alignment - 1); } template inline void *RoundUp(T *t, unsigned int alignment) { u32 value = reinterpret_cast(t); u32 rounded = (alignment + value - 1) & ~(alignment - 1); return reinterpret_cast(rounded); } template inline T RoundDown(T t, unsigned int alignment) { return t & ~(alignment - 1); } template inline void *RoundDown(T *t, unsigned int alignment) { u32 value = reinterpret_cast(t); u32 rounded = value & ~(alignment - 1); return reinterpret_cast(rounded); } } // namespace } // namespace ut } // namespace nw4r #endif