159 lines
6.0 KiB
C++
159 lines
6.0 KiB
C++
// =====================================================================================================================
|
|
// 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/>.
|
|
// =====================================================================================================================
|
|
|
|
|
|
#ifndef FENNEC_MEMORY_H
|
|
#define FENNEC_MEMORY_H
|
|
|
|
#include <fennec/lang/type_traits.h>
|
|
#include <fennec/memory/detail/__memory.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); }
|
|
|
|
///
|
|
/// \copydetails fennec::memchr(const void*, int, size_t)
|
|
constexpr void* memchr(void* arr, int ch, size_t n)
|
|
{
|
|
uint8_t* a = static_cast<uint8_t*>(arr);
|
|
while (n--) if (*a++ == ch) return a - 1;
|
|
return nullptr;
|
|
}
|
|
|
|
///
|
|
/// \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.
|
|
constexpr const void* memchr(const void* arr, int ch, size_t n)
|
|
{
|
|
const uint8_t* a = static_cast<const uint8_t*>(arr);
|
|
while (n--) if (*a++ == ch) return a - 1;
|
|
return nullptr;
|
|
}
|
|
|
|
///
|
|
/// \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$
|
|
constexpr int memcmp(const void* lhs, const void* rhs, size_t n)
|
|
{
|
|
const uint8_t* lhs_ = static_cast<const uint8_t*>(lhs);
|
|
const uint8_t* rhs_ = static_cast<const uint8_t*>(rhs);
|
|
|
|
while (n--)
|
|
if (*lhs_++ != *rhs_++)
|
|
return lhs_[-1] - rhs_[-1];
|
|
|
|
return 0;
|
|
}
|
|
|
|
///
|
|
/// \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.
|
|
constexpr void* memcpy(void* dst, const void* src, size_t n)
|
|
{
|
|
if (dst == src) return dst;
|
|
uint8_t* d = static_cast<uint8_t*>(dst);
|
|
const uint8_t* s = static_cast<const uint8_t*>(src);
|
|
|
|
while (n >= 8) { detail::__memcpy_64(d, s); d += 8; s += 8; n -= 8; }
|
|
while (n >= 4) { detail::__memcpy_32(d, s); d += 4; s += 4; n -= 4; }
|
|
while (n >= 2) { detail::__memcpy_16(d, s); d += 2; s += 2; n -= 2; }
|
|
while (n >= 1) { *d++ = *s++; --n; }
|
|
|
|
return dst;
|
|
}
|
|
|
|
///
|
|
/// \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$
|
|
constexpr void* memmove(void* dst, const void* src, size_t n)
|
|
{
|
|
if (dst == src) return dst;
|
|
uint8_t* d = static_cast<uint8_t*>(dst);
|
|
const uint8_t* s = static_cast<const uint8_t*>(src);
|
|
|
|
if (d < s)
|
|
{
|
|
while (n >= 8) { detail::__memcpy_64(d, s); d += 8; s += 8; n -= 8; }
|
|
while (n >= 4) { detail::__memcpy_32(d, s); d += 4; s += 4; n -= 4; }
|
|
while (n >= 2) { detail::__memcpy_16(d, s); d += 2; s += 2; n -= 2; }
|
|
while (n >= 1) { *d++ = *s++; --n; }
|
|
}
|
|
else
|
|
{
|
|
d += n - 1; s += n - 1;
|
|
while (n >= 8) { detail::__memcpy_64(d, s); d -= 8; s -= 8; n -= 8; }
|
|
while (n >= 4) { detail::__memcpy_32(d, s); d -= 4; s -= 4; n -= 4; }
|
|
while (n >= 2) { detail::__memcpy_16(d, s); d -= 2; s -= 2; n -= 2; }
|
|
while (n >= 1) { *d-- = *s--; --n; }
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
///
|
|
/// \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$
|
|
constexpr void* memset(void* dst, int ch, size_t n)
|
|
{
|
|
uint8_t* d = static_cast<uint8_t*>(dst);
|
|
uint8_t val8 = ch;
|
|
uint16_t val16 = (static_cast<uint16_t>(val8) << 8) | static_cast<int16_t>(val8);
|
|
uint32_t val32 = (static_cast<uint32_t>(val16) << 16) | static_cast<int32_t>(val16);
|
|
uint64_t val64 = (static_cast<uint64_t>(val32) << 32) | static_cast<int64_t>(val32);
|
|
|
|
while (n >= 8) { detail::__memcpy_64(d, &val64); d += 8; n -= 8; }
|
|
while (n >= 4) { detail::__memcpy_32(d, &val32); d += 4; n -= 4; }
|
|
while (n >= 2) { detail::__memcpy_16(d, &val16); d += 2; n -= 2; }
|
|
while (n >= 1) { *d++ = val8; --n; }
|
|
|
|
return dst;
|
|
}
|
|
|
|
}
|
|
|
|
#endif // FENNEC_MEMORY_H
|