#include <psemek/util/dynamic_bitset.hpp>

#include <bit>

namespace psemek::util
{

	[[nodiscard]] bool operator == (dynamic_bitset const & b1, dynamic_bitset const & b2)
	{
		auto storage1 = b1.storage();
		auto storage2 = b2.storage();

		auto const min_size = std::min(storage1.size(), storage2.size());

		std::size_t i = 0;
		for (; i < min_size; ++i)
			if (storage1[i] != storage2[i])
				return false;

		if (storage1.size() < storage2.size())
		{
			for (; i < storage2.size(); ++i)
				if (0 != storage2[i])
					return false;
		}
		else
		{
			for (; i < storage1.size(); ++i)
				if (storage1[i] != 0)
					return false;
		}

		return true;
	}

	[[nodiscard]] std::strong_ordering operator <=> (dynamic_bitset const & b1, dynamic_bitset const & b2)
	{
		auto storage1 = b1.storage();
		auto storage2 = b2.storage();

		auto const min_size = std::min(storage1.size(), storage2.size());

		std::size_t i = 0;
		for (; i < min_size; ++i)
			if (auto res = storage1[i] <=> storage2[i]; res != std::strong_ordering::equal)
				return res;

		if (storage1.size() < storage2.size())
		{
			for (; i < storage2.size(); ++i)
				if (auto res = 0 <=> storage2[i]; res != std::strong_ordering::equal)
					return res;
		}
		else
		{
			for (; i < storage1.size(); ++i)
				if (auto res = storage1[i] <=> 0; res != std::strong_ordering::equal)
					return res;
		}

		return std::strong_ordering::equal;
	}

	[[nodiscard]] bool is_subset(dynamic_bitset const & b1, dynamic_bitset const & b2)
	{
		auto storage1 = b1.storage();
		auto storage2 = b2.storage();

		auto const min_size = std::min(storage1.size(), storage2.size());

		std::size_t i = 0;
		for (; i < min_size; ++i)
			if ((storage1[i] & storage2[i]) != storage1[i])
				return false;

		if (storage1.size() > storage2.size())
		{
			for (; i < storage1.size(); ++i)
				if (storage1[i] != 0)
					return false;
		}

		return true;
	}

	[[nodiscard]] std::size_t popcount(dynamic_bitset const & b)
	{
		std::size_t result = 0;
		for (auto value : b.storage())
			result += std::popcount(value);
		return result;
	}

}
