// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright (C) 2025  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 common.h
/// \brief This header contains functions related to analyzing, modifying or copying buffers interpreted as bytes
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 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
{

///
/// \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);
}

///
/// \brief Finds the first occurence of ```static_cast<uint8_t>(ch)``` in the first \f$n\f$ 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 \f$ch\f$, otherwise \f$nullptr\f$ if \f$ch\f$ is not found.
using ::memchr;
using ::wmemchr;

///
/// \brief Compares the bytes of \f$lhs\f$ with \f$rhs\f$.
/// \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 \f$0\f$ if the first \f$n\f$ bytes of \f$lhs\f$ and \f$rhs\f$ are equivalent. Otherwise, returns \f$1\f$
///          for the first byte \f$b\f$ where \f$lhs[b] > \f$ rhs[b]\f$, and \f$-1\f$ for \f$
using ::memcmp;
using ::wmemcmp;

///
/// \brief Safe version of memcmp
/// \copydoc fennec::memcmp
/// \param n0 The size, in bytes, of lhs
/// \param n1 The size, in bytes, of rhs
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 Copies the first \f$n\f$ bytes of \f$src\f$ to \f$dst\f$.
/// \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 \f$dst\f$
///
/// \details memcpy does not do any checking for whether \f$dst\f$ and \f$src\f$ overlap. Let \f$k\f$ be the number of
///          bytes of which \f$dst\f$ and \f$src\f$. If \f$k > 0 & src < dst\f$ then the first \f$k\f$ elements of
///          \f$src\f$ will be repeated in \f$dst\f$ with a period of \f$k\f$.
///
///          A full mathematical proof of this function is possible in Set Theory.
using ::memcpy;
using ::wmemcpy;

///
/// \brief Safe version of memcpy
/// \copydoc fennec::memcpy
/// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src
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 \f$n\f$ bytes of \f$src\f$ to \f$dst\f$, 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 \f$dst\f$
using ::memmove;
using ::wmemmove;

///
/// \brief Safe version of memmove
/// \copydoc fennec::memmove
/// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src
constexpr void* memmove_s(void* dst, size_t n0, const void* src, size_t n1) {
	return memmove(dst, src, n0 < n1 ? n0 : n1);
}

///
/// \brief Sets all bytes of \f$dst\f$ to \f$ch\f$, interpreted as an \f$uint8_t\f$
/// \param dst The destination object, interpreted as an array of bytes
/// \param ch The value, interpreted as an \f$uint8_t\f$
/// \param n The number of bytes to set
/// \returns \f$dst\f$
using ::memset;
using ::wmemset;

}

#endif // FENNEC_MEMORY_H
