#pragma once

#include <type_traits>

namespace psemek::util
{

	template <typename T>
	bool is_pow2(T x)
	{
		static_assert(std::is_integral_v<T>);

		return (x > 0) && ((x & (x - 1)) == 0);
	}

	// log2 rounded down
	template <typename T>
	T log2(T x)
	{
		T result = 0;
		while (x > 1)
		{
			++result;
			x /= 2;
		}
		return result;
	}

	// round up to power of 2
	template <typename T>
	T round_pow2(T x)
	{
		static_assert(std::is_integral_v<T>);
		static_assert(std::is_unsigned_v<T>);

		x--;
		x |= x >> 1;
		x |= x >> 2;
		x |= x >> 4;
		if constexpr (sizeof(T) >= 2)
			x |= x >> 8;
		if constexpr (sizeof(T) >= 4)
			x |= x >> 16;
		if constexpr (sizeof(T) >= 8)
			x |= x >> 32;
		x++;

		return x;
	}

}
