/**
 * @file Math.h
 * @brief 数学工具函数与二进制对齐辅助函数。
 * @details
 * 提供模板化的数值打包/解包与内存对齐能力，包括：
 * - clamp 与归一化浮点量化打包；
 * - 固定/动态对齐粒度下的向上与向下对齐；
 * - 基于 SIMD 指令的 CRC32 快速计算辅助。
 */
#pragma once
#include "CommonHeader.h"
#include "MathTypes.h"

namespace XEngine::math {

/**
 * @brief 将值限制在给定区间内。
 * @tparam T 标量类型。
 * @param value 输入值。
 * @param min 下界。
 * @param max 上界。
 * @return 限制后的值。
 */
template<typename T>
[[nodiscard]] constexpr T 
clamp(T value, T min, T max)
{
	return (value < min) ? min : (value > max) ? max : value;
}


/**
 * @brief 将 [0,1] 浮点值量化到指定位宽的无符号整数。
 * @tparam bits 量化位宽。
 * @param i 归一化输入值。
 * @return 量化结果。
 */
template<u32 bits>
[[nodiscard]] constexpr u32 
pack_unit_float(f32 i)
{
	static_assert(bits <= sizeof(u32) * 8);
	assert(i >= 0.f && i <= 1.f);
	constexpr f32 intervals{ (f32)(((u32)1 << bits) - 1) };
	return (u32)(intervals * i + 0.5f);
}

/**
 * @brief 将 [min,max] 浮点值量化到指定位宽。
 * @tparam bits 量化位宽。
 * @param i 输入值。
 * @param min 下界。
 * @param max 上界。
 * @return 量化结果。
 */
template<u32 bits>
[[nodiscard]] constexpr u32 
pack_float(f32 i, f32 min, f32 max)
{
	assert(min < max);
	assert(i <= max && i >= min);
	const f32 distance{ (i - min) / (max - min) };
	return pack_unit_float<bits>(distance);
}



/**
 * @brief 将量化整数还原为 [0,1] 浮点值。
 * @tparam bits 量化位宽。
 * @param i 量化输入值。
 * @return 反量化结果。
 */
template<u32 bits>
[[nodiscard]] constexpr f32 
unpack_unit_float(u32 i)
{
	static_assert(bits <= sizeof(u32) * 8);
	assert(i < ((u32)i << bits));
	constexpr f32 intervals{ (f32)(((u32)1 << bits) - 1) };
	return (f32)i / intervals;
}


/**
 * @brief 将量化值还原到 [min,max] 区间。
 * @tparam bits 量化位宽。
 * @param i 量化输入值。
 * @param min 下界。
 * @param max 上界。
 * @return 反量化结果。
 */
template<u32 bits>
[[nodiscard]] constexpr f32 
unpack_float(f32 i, f32 min, f32 max)
{
	assert(min < max);
	return unpack_unit_float<bits>(i) * (max - min) + min;
}

/**
 * @brief 按固定对齐值向上对齐。
 * @tparam alignment 对齐粒度（2 的幂）。
 * @param size 原始大小。
 * @return 向上对齐后的大小。
 */
template<u64 alignment>
[[nodiscard]] constexpr u64 
align_size_up(u64 size)
{
	static_assert(alignment, "Alignment must be non-zero.");
	constexpr u64 mask{ alignment - 1 };
	static_assert(!(alignment & mask), "Alignment should be a power of 2.");
	return ((size + mask) & ~mask);
}

/**
 * @brief 按固定对齐值向下对齐。
 * @tparam alignment 对齐粒度（2 的幂）。
 * @param size 原始大小。
 * @return 向下对齐后的大小。
 */
template<u64 alignment>
[[nodiscard]]  constexpr u64 
align_size_down(u64 size)
{
	static_assert(alignment, "Alignment must be non-zero.");
	constexpr u64 mask{ alignment - 1 };
	static_assert(!(alignment & mask), "Alignment should be a power of 2.");
	return (size  & ~mask);
}

/**
 * @brief 按运行时对齐值向上对齐。
 * @param size 原始大小。
 * @param alignment 对齐粒度（2 的幂）。
 * @return 向上对齐后的大小。
 */
[[nodiscard]] constexpr u64
align_size_up(u64 size, u64 alignment)
{
	assert(alignment && "Alignment must be non-zero.");
	const u64 mask{ alignment - 1 };
	assert(!(alignment & mask) && "Alignment should be a power of 2.");
	return ((size + mask) & ~mask);
}

/**
 * @brief 按运行时对齐值向下对齐。
 * @param size 原始大小。
 * @param alignment 对齐粒度（2 的幂）。
 * @return 向下对齐后的大小。
 */
[[nodiscard]] constexpr u64
align_size_down(u64 size, u64 alignment)
{
	assert(alignment && "Alignment must be non-zero.");
	const u64 mask{ alignment - 1 };
	assert(!(alignment & mask) && "Alignment should be a power of 2.");
	return (size & ~mask);
}

/**
 * @brief 计算数据块的 64 位 CRC32 累积值。
 * @param data 输入字节流。
 * @param size 输入长度。
 * @return CRC32 累积结果。
 */
[[nodiscard]] constexpr u64 
calcect_crc32_u64(const u8 *const data, u64 size)
{
	assert(size >= sizeof(u64));
	u64 crc{ 0 };
	const u8* at{ data };
	const u8 *const end{ data + align_size_down<sizeof(u64)>(size) };
	while (at < end)
	{
		crc = _mm_crc32_u64(crc, *((const u64*)at));
		at += sizeof(u64);
	}

	return crc;
}

}
