// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025 - 2026  Medusa Slockbower
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

///
/// \file fennec/lang/bits.h
/// \brief \ref fennec_lang_bit_manipulation
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///

#ifndef FENNEC_LANG_BITS_H
#define FENNEC_LANG_BITS_H

///
/// \page fennec_lang_bit_manipulation Bit Manipulation
///
/// \code #include <fennec/lang/bits.h> \endcode
///
/// This header contains definitions for manipulating the bits of a provided object or pointer.
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_bits">
/// <tr><th style="vertical-align: top">Syntax
///     <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::bit_cast "ToT bit_cast(const FromT& x)"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::bit_cast
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::bit_and "void* bit_and(void* arr, const void* mask, size_t n)"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::bit_and
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::bit_and_s "void* bit_and_s(void* arr, size_t n0, const void* mask, size_t n1)"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::bit_and_s
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::bit_or "void* bit_or(void* arr, const void* mask, size_t n)"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::bit_or
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::bit_or_s "void* bit_or_s(void* arr, size_t n0, const void* mask, size_t n1)"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::bit_or_s
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::bit_xor "void* bit_xor(void* arr, const void* mask, size_t n)"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::bit_xor
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::bit_xor_s "void* bit_xor_s(void* arr, size_t n0, const void* mask, size_t n1)"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::bit_xor_s
/// </table>
///
///

#include <fennec/lang/intrinsics.h>
#include <fennec/memory/common.h>
#include <fennec/lang/detail/_bits.h>

namespace fennec
{

///
/// \brief Perform a bitcast of FromT to ToT
///
/// \details Perform a bitcast of FromT to ToT
/// \tparam ToT Type to cast to
/// \tparam FromT Type of the value
/// \param from Value to bit cast
/// \returns A value containing a bitwise copy of the input
template<typename ToT, typename FromT> requires(sizeof(ToT) == sizeof(FromT))
constexpr ToT bit_cast(const FromT& from) {
	if constexpr(FENNEC_HAS_BUILTIN_BIT_CAST) {
		return FENNEC_BUILTIN_BIT_CAST(ToT, from);
	} else {
		ToT to;
		fennec::memcpy(&to, &from, sizeof(ToT));
		return to;
	}
}





///
/// \brief Perform a bit-wise and over an array of bytes
///
/// \details Perform a bitcast of FromT to ToT
/// \param arr the array of bytes to modify
/// \param mask the mask to and against arr
/// \param n the number of bytes
/// \returns the pointer \emph{arr}
constexpr void* bit_and(void* arr, const void* mask, size_t n) {
	if (arr == mask) {
		return arr;
	}

	uint8_t*       d = static_cast<uint8_t*>(arr);
	const uint8_t* s = static_cast<const uint8_t*>(mask);

	while (n > 0) {
		const size_t step = detail::_bit_and(d, s, n);
		d += step; s += step; n -= step;
	}

	return arr;
}

///
/// \brief Safe version of fennec::bit_and
///
/// \details Safe version of fennec::bit_and
/// \param arr the array of bytes to modify
/// \param n0 the size of arr in bytes
/// \param mask the mask to and against arr
/// \param n1 the size of mask in bytes
/// \returns the pointer arr
constexpr void* bit_and_s(void* arr, size_t n0, const void* mask, size_t n1) {
	return bit_and(arr, mask, n0 < n1 ? n0 : n1);
}





///
/// \brief Perform a bit-wise or over an array of bytes
///
/// \details Perform a bit-wise or over an array of bytes
/// \param arr the array of bytes to modify
/// \param mask the mask to or against arr
/// \param n the number of bytes
/// \returns the pointer arr
constexpr void* bit_or(void* arr, const void* mask, size_t n) {
	if (arr == mask) {
		return arr;
	}

	uint8_t*       d = static_cast<uint8_t*>(arr);
	const uint8_t* s = static_cast<const uint8_t*>(mask);
	while (n > 0)
	{
		const size_t step = detail::_bit_or(d, s, n);
		d += step; s += step; n -= step;
	}

	return arr;
}

///
/// \brief Safe version of fennec::bit_or
///
/// \details Safe version of fennec::bit_or
/// \param arr the array of bytes to modify
/// \param n0 the size of arr in bytes
/// \param mask the mask to or against arr
/// \param n1 the size of mask in bytes
/// \returns the pointer arr
constexpr void* bit_or_s(void* arr, size_t n0, const void* mask, size_t n1) {
	return bit_or(arr, mask, n0 < n1 ? n0 : n1);
}





///
/// \brief Perform a bit-wise or over an array of bytes
///
/// \details Perform a bit-wise or over an array of bytes
/// \param arr the array of bytes to modify
/// \param mask the mask to or against arr
/// \param n the number of bytes
/// \returns the pointer arr
constexpr void* bit_xor(void* arr, const void* mask, size_t n) {
	if (arr == mask) {
		return arr;
	}

	uint8_t*       d = static_cast<uint8_t*>(arr);
	const uint8_t* s = static_cast<const uint8_t*>(mask);
	while (n > 0) {
		const size_t step = detail::_bit_xor(d, s, n);
		d += step; s += step; n -= step;
	}

	return arr;
}

///
/// \brief Safe version of fennec::bit_xor
///
/// \details Safe version of fennec::bit_xor
/// \param arr the array of bytes to modify
/// \param n0 the size of arr in bytes
/// \param mask the mask to or against arr
/// \param n1 the size of mask in bytes
/// \returns the pointer arr
constexpr void* bit_xor_s(void* arr, size_t n0, const void* mask, size_t n1) {
	return bit_xor(arr, mask, n0 < n1 ? n0 : n1);
}

}

#endif // FENNEC_LANG_BITS_H
