// =====================================================================================================================
//  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/memory/common.h
/// \brief This header contains functions related to analyzing, modifying or copying buffers interpreted as bytes
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///


#ifndef FENNEC_MEMORY_H
#define FENNEC_MEMORY_H

#include <fennec/lang/type_traits.h>
#include <fennec/memory/detail/_string.h>

namespace fennec
{

// addressof ===========================================================================================================

///
/// \brief Returns the address of an object regardless of whether the `&` operators is implemented.
/// \tparam TypeT The type of the objects
/// \param obj The object to find the address of
/// \return The true address of the
template<typename TypeT>
constexpr TypeT* addressof(TypeT& obj) {
	return FENNEC_BUILTIN_ADDRESSOF(obj);
}



// memchr ==============================================================================================================

///
/// \brief Finds the first occurrence of `static_cast<uint8_t>(ch)` in the first \emph{n} bytes
/// \param arr Pointer to the object, interpreted as an array of bytes
/// \param ch The byte to search for
/// \param n The number of bytes to search
/// \returns A pointer to the location of \emph{ch}, otherwise \emph{nullptr} if \emph{ch} is not found.
constexpr const void* memchr(const void* arr, int ch, size_t n) {
	return ::memchr(arr, ch, n);
}

///
/// \brief Finds the first occurrence of `static_cast<wchar_t>(ch)` in the first \emph{n} characters
/// \param arr Pointer to the object, interpreted as an array of \emph{wchar_t}
/// \param ch The byte to search for
/// \param n The number of characters to search
/// \returns A pointer to the location of \emph{ch}, otherwise \emph{nullptr} if \emph{ch} is not found.
constexpr const wchar_t* wmemchr(const wchar_t* arr, wchar_t ch, size_t n) {
	return ::wmemchr(arr, ch, n);
}



// memcmp ==============================================================================================================

///
/// \brief Compares the bytes of \emph{lhs} with \emph{rhs}.
/// \param lhs The first object, interpreted as an array of bytes
/// \param rhs The second object, interpreted as an array of bytes
/// \param n The number of bytes to parse
/// \returns \math{0} if the first \emph{n} bytes of \emph{lhs} and \emph{rhs} are equivalent. Otherwise, returns a positive value
///          for the first byte \math{b} where \math{\textbf{lhs}[b] > \textbf{rhs}[b]}, and a negative value
///          for the first byte \math{b} where \math{\textbf{lhs}[b] < \textbf{rhs}[b]}
constexpr int memcmp(const void* lhs, const void* rhs, size_t n) {
	return ::memcmp(lhs, rhs, n);
}

///
/// \brief Safe version of memcmp
/// \param lhs The first object, interpreted as an array of bytes
/// \param rhs The second object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of lhs
/// \param n1 The size, in bytes, of rhs
/// \returns \math{0} if the first \emph{min(n0, n1)} bytes of \emph{lhs} and \emph{rhs} are equivalent. Otherwise, returns a positive value
///          for the first byte \math{b} where \math{\textbf{lhs}[b] > \textbf{rhs}[b]}, and a negative value
///          for the first byte \math{b} where \math{\textbf{lhs}[b] < \textbf{rhs}[b]}
constexpr int memcmp_s(const void* lhs, size_t n0, const void* rhs, size_t n1) {
	return ::memcmp(lhs, rhs, n0 < n1 ? n0 : n1);
}


///
/// \brief Compares the characters of \emph{lhs} with \emph{rhs}.
/// \param lhs The first object, interpreted as an array of \emph{wchar_t}
/// \param rhs The second object, interpreted as an array of \emph{wchar_t}
/// \param n The number of characters to parse
/// \returns \emph{0} if the first \emph{n} characters of \emph{lhs} and \emph{rhs} are equivalent. Otherwise, returns a positive value
///          for the first character \math{c} where \math{\textbf{lhs}[c] > \textbf{rhs}[c]}, and a negative value
///          for the first character \math{c} where \math{\textbf{lhs}[c] < \textbf{rhs}[c]}
constexpr int wmemcmp(const wchar_t* lhs, const wchar_t* rhs, size_t n) {
	return ::wmemcmp(lhs, rhs, n);
}

///
/// \brief Safe version of memcmp
/// \param lhs The first object, interpreted as an array of \emph{wchar_t}
/// \param rhs The second object, interpreted as an array of \emph{wchar_t}
/// \param n0 The size, in characters, of lhs
/// \param n1 The size, in characters, of rhs
/// \returns \emph{0} if the first \emph{min(n0, n1)} character of \emph{lhs} and \emph{rhs} are equivalent. Otherwise, returns a positive value
///          for the first character \math{c} where \math{\textbf{lhs}[c] > \textbf{rhs}[c]}, and a negative value
///          for the first character \math{c} where \math{\textbf{lhs}[c] < \textbf{rhs}[c]}
constexpr int wmemcmp_s(const wchar_t* lhs, size_t n0, const wchar_t* rhs, size_t n1) {
	return ::wmemcmp(lhs, rhs, n0 < n1 ? n0 : n1);
}



// memcmp ==============================================================================================================

///
/// \brief Copies the first \emph{n} bytes of \emph{src} to \emph{dst}.
/// \param dst The destination object, interpreted as an array of bytes
/// \param src The source object, interpreted as an array of bytes
/// \param n The number of bytes to copy
/// \returns \emph{dst}
///
/// \details memcpy does not do any checking for whether \emph{dst} and \emph{src} overlap. Let \math{k} be the offset
///          by which \emph{dst} and \emph{src} overlap. If \math{k > 0 & \textbf{src} < \textbf{dst}} then the first \math{k} elements of
///          \emph{src} will be repeated in \emph{dst} with a period of \math{k}.
///
///          A full mathematical proof of this function is possible in Set Theory.
constexpr void* memcpy(void* dst, const void* src, size_t n) {
	return ::memcpy(dst, src, n);
}

///
/// \brief Safe version of memcpy
/// \param dst The destination object, interpreted as an array of bytes
/// \param src The source object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src
/// \returns \emph{dst}
///
/// \details memcpy does not do any checking for whether \emph{dst} and \emph{src} overlap. Let \math{k} be the offset
///          by which \emph{dst} and \emph{src} overlap. If \math{k > 0 & \textbf{src} < \textbf{dst}} then the first \math{k} elements of
///          \emph{src} will be repeated in \emph{dst} with a period of \math{k}.
///
///          A full mathematical proof of this function is possible in Set Theory.
constexpr void* memcpy_s(void* dst, size_t n0, const void* src, size_t n1) {
	return ::memcpy(dst, src, n0 < n1 ? n0 : n1);
}


///
/// \brief Copies the first \emph{n} characters of \emph{src} to \emph{dst}.
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param src The source object, interpreted as an array of \emph{wchar_t}
/// \param n The number of characters to copy
/// \returns \emph{dst}
///
/// \details wmemcpy does not do any checking for whether \emph{dst} and \emph{src} overlap. Let \math{k} be the offset
///          by which \emph{dst} and \emph{src} overlap. If \math{k > 0 & \textbf{src} < \textbf{dst}} then the first \math{k} elements of
///          \emph{src} will be repeated in \emph{dst} with a period of \math{k}.
///
///          A full mathematical proof of this function is possible in Set Theory.
constexpr void* wmemcpy(wchar_t* dst, const wchar_t* src, size_t n) {
	return ::wmemcpy(dst, src, n);
}

///
/// \brief Safe version of wmemcpy
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param src The source object, interpreted as an array of \emph{wchar_t}
/// \param n0 The size, in characters, of dst
/// \param n1 The size, in characters, of src
/// \returns \emph{dst}
///
/// \details wmemcpy does not do any checking for whether \emph{dst} and \emph{src} overlap. Let \math{k} be the offset
///          by which \emph{dst} and \emph{src} overlap. If \math{k > 0 & \textbf{src} < \textbf{dst}} then the first \math{k} elements of
///          \emph{src} will be repeated in \emph{dst} with a period of \math{k}.
///
///          A full mathematical proof of this function is possible in Set Theory.
constexpr void* wmemcpy_s(wchar_t* dst, size_t n0, const wchar_t* src, size_t n1) {
	return ::wmemcpy(dst, src, n0 < n1 ? n0 : n1);
}



// memmove =============================================================================================================

///
/// \brief Copies the first \emph{n} bytes of \emph{src} to \emph{dst}, with overlap correction.
/// \param dst The destination object, interpreted as an array of bytes
/// \param src The source object, interpreted as an array of bytes
/// \param n The number of bytes to copy
/// \returns \emph{dst}
constexpr void* memmove(void* dst, const void* src, size_t n) {
	return ::memmove(dst, src, n);
}

///
/// \brief Safe version of memmove
/// \param dst The destination object, interpreted as an array of bytes
/// \param src The source object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src
/// \returns \emph{dst}
constexpr void* memmove_s(void* dst, size_t n0, const void* src, size_t n1) {
	return ::memmove(dst, src, n0 < n1 ? n0 : n1);
}


///
/// \brief Copies the first \emph{n} characters of \emph{src} to \emph{dst}, with overlap correction.
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param src The source object, interpreted as an array of \emph{wchar_t}
/// \param n The number of characters to copy
/// \returns \emph{dst}
constexpr void* wmemmove(wchar_t* dst, const wchar_t* src, size_t n) {
	return ::wmemmove(dst, src, n);
}

///
/// \brief Safe version of wmemmove
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param src The source object, interpreted as an array of \emph{wchar_t}
/// \param n0 The size, in characters, of dst
/// \param n1 The size, in characters, of src
/// \returns \emph{dst}
constexpr wchar_t* wmemmove_s(wchar_t* dst, size_t n0, const wchar_t* src, size_t n1) {
	return ::wmemmove(dst, src, n0 < n1 ? n0 : n1);
}



// memset ==============================================================================================================

///
/// \brief Sets all bytes of \emph{dst} to \emph{ch}, interpreted as an \emph{uint8_t}
/// \param dst The destination object, interpreted as an array of bytes
/// \param ch The value, interpreted as an \emph{uint8_t}
/// \param n The number of bytes to set
constexpr void memset(void* dst, int ch, size_t n) {
	::memset(dst, ch, n);
}

///
/// \brief Sets all characters of \emph{dst} to \emph{ch}
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param ch The value, interpreted as an \emph{uint8_t}
/// \param n The number of characters to set
constexpr void wmemset(wchar_t* dst, wchar_t ch, size_t n) {
	::wmemset(dst, ch, n);
}

}

#endif // FENNEC_MEMORY_H
