170 lines
5.3 KiB
C++
170 lines
5.3 KiB
C++
|
// Copyright (C) 2023 RozK
|
||
|
//
|
||
|
// This program is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU Affero General Public License
|
||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
#ifndef RK_ENGINE_CMP_MEMCPY_H
|
||
|
#define RK_ENGINE_CMP_MEMCPY_H
|
||
|
|
||
|
#include "types.hpp"
|
||
|
|
||
|
template<typename _type>
|
||
|
bool _rk_cmp_memcpy_small(
|
||
|
void * const __restrict _dst,
|
||
|
void const * const __restrict _src,
|
||
|
unsigned const size) {
|
||
|
unsigned count = (size / sizeof(_type));
|
||
|
_type * dst = reinterpret_cast<_type *>(_dst);
|
||
|
_type const * src = reinterpret_cast<_type const *>(_src);
|
||
|
_type cmp = 0;
|
||
|
do {
|
||
|
cmp |= *dst ^ *src;
|
||
|
*dst++ = *src++;
|
||
|
} while(--count > 0);
|
||
|
return (cmp != 0);
|
||
|
}
|
||
|
|
||
|
template<typename _big, typename _small>
|
||
|
bool _rk_cmp_memcpy_big(
|
||
|
void * const __restrict _dst,
|
||
|
void const * const __restrict _src,
|
||
|
unsigned const size) {
|
||
|
unsigned count = size / sizeof(_big);
|
||
|
unsigned const remain = size % sizeof(_big);
|
||
|
_big * dst = reinterpret_cast<_big *>(_dst);
|
||
|
_big const * src = reinterpret_cast<_big const *>(_src);
|
||
|
_big cmp = 0;
|
||
|
do {
|
||
|
cmp |= *dst ^ *src;
|
||
|
*dst++ = *src++;
|
||
|
} while(--count > 0);
|
||
|
bool modified = (cmp != 0);
|
||
|
if (remain) {
|
||
|
modified |= _rk_cmp_memcpy_small<_small>(dst, src, remain);
|
||
|
}
|
||
|
return modified;
|
||
|
}
|
||
|
|
||
|
#ifdef RK_CMP_MEMCPY_UNALIGNED
|
||
|
#define _rk_size_and_alignment(_t) (size >= sizeof(_t))
|
||
|
#else
|
||
|
#define _rk_size_and_alignment(_t) (size >= sizeof(_t) && !(alignment & (sizeof(_t) - 1)))
|
||
|
#endif
|
||
|
|
||
|
template<unsigned _s>
|
||
|
bool rk_cmp_memcpy(
|
||
|
void * const __restrict _dst,
|
||
|
void const * const __restrict _src,
|
||
|
unsigned const size);
|
||
|
|
||
|
template<>
|
||
|
bool rk_cmp_memcpy<sizeof(rk_ubyte)>(
|
||
|
void * const __restrict _dst,
|
||
|
void const * const __restrict _src,
|
||
|
unsigned const size) {
|
||
|
#ifndef RK_CMP_MEMCPY_UNALIGNED
|
||
|
unsigned const alignment = reinterpret_cast<uintptr_t>(_dst) | reinterpret_cast<uintptr_t const>(_src);
|
||
|
#endif
|
||
|
if (_rk_size_and_alignment(rk_ullong)) {
|
||
|
return _rk_cmp_memcpy_big<rk_ullong, rk_ubyte>(_dst, _src, size);
|
||
|
}
|
||
|
if (_rk_size_and_alignment(rk_ulong)) {
|
||
|
return _rk_cmp_memcpy_big<rk_ulong, rk_ubyte>(_dst, _src, size);
|
||
|
}
|
||
|
if (_rk_size_and_alignment(rk_uint)) {
|
||
|
return _rk_cmp_memcpy_big<rk_uint, rk_ubyte>(_dst, _src, size);
|
||
|
}
|
||
|
if (_rk_size_and_alignment(rk_ushort)) {
|
||
|
return _rk_cmp_memcpy_big<rk_ushort, rk_ubyte>(_dst, _src, size);
|
||
|
}
|
||
|
if (size > 0) {
|
||
|
return _rk_cmp_memcpy_small<rk_ubyte>(_dst, _src, size);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
bool rk_cmp_memcpy<sizeof(rk_ushort)>(
|
||
|
void * const __restrict _dst,
|
||
|
void const * const __restrict _src,
|
||
|
unsigned const size) {
|
||
|
#ifndef RK_CMP_MEMCPY_UNALIGNED
|
||
|
unsigned const alignment = reinterpret_cast<uintptr_t>(_dst) | reinterpret_cast<uintptr_t const>(_src);
|
||
|
#endif
|
||
|
if (_rk_size_and_alignment(rk_ullong)) {
|
||
|
return _rk_cmp_memcpy_big<rk_ullong, rk_ushort>(_dst, _src, size);
|
||
|
}
|
||
|
if (_rk_size_and_alignment(rk_ulong)) {
|
||
|
return _rk_cmp_memcpy_big<rk_ulong, rk_ushort>(_dst, _src, size);
|
||
|
}
|
||
|
if (_rk_size_and_alignment(rk_uint)) {
|
||
|
return _rk_cmp_memcpy_big<rk_uint, rk_ushort>(_dst, _src, size);
|
||
|
}
|
||
|
if (size > 0) {
|
||
|
return _rk_cmp_memcpy_small<rk_ushort>(_dst, _src, size);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
bool rk_cmp_memcpy<sizeof(rk_uint)>(
|
||
|
void * const __restrict _dst,
|
||
|
void const * const __restrict _src,
|
||
|
unsigned const size) {
|
||
|
#ifndef RK_CMP_MEMCPY_UNALIGNED
|
||
|
unsigned const alignment = reinterpret_cast<uintptr_t>(_dst) | reinterpret_cast<uintptr_t const>(_src);
|
||
|
#endif
|
||
|
if (_rk_size_and_alignment(rk_ullong)) {
|
||
|
return _rk_cmp_memcpy_big<rk_ullong, rk_uint>(_dst, _src, size);
|
||
|
}
|
||
|
if (_rk_size_and_alignment(rk_ulong)) {
|
||
|
return _rk_cmp_memcpy_big<rk_ulong, rk_uint>(_dst, _src, size);
|
||
|
}
|
||
|
if (size > 0) {
|
||
|
return _rk_cmp_memcpy_small<rk_uint>(_dst, _src, size);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
bool rk_cmp_memcpy<sizeof(rk_ulong)>(
|
||
|
void * const __restrict _dst,
|
||
|
void const * const __restrict _src,
|
||
|
unsigned const size) {
|
||
|
#ifndef RK_CMP_MEMCPY_UNALIGNED
|
||
|
unsigned const alignment = reinterpret_cast<uintptr_t>(_dst) | reinterpret_cast<uintptr_t const>(_src);
|
||
|
#endif
|
||
|
if (_rk_size_and_alignment(rk_ullong)) {
|
||
|
return _rk_cmp_memcpy_big<rk_ullong, rk_ulong>(_dst, _src, size);
|
||
|
}
|
||
|
if (size > 0) {
|
||
|
return _rk_cmp_memcpy_small<rk_ulong>(_dst, _src, size);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
bool rk_cmp_memcpy<sizeof(rk_ullong)>(
|
||
|
void * const __restrict _dst,
|
||
|
void const * const __restrict _src,
|
||
|
unsigned const size) {
|
||
|
if (size > 0) {
|
||
|
return _rk_cmp_memcpy_small<rk_ullong>(_dst, _src, size);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#undef _rk_size_and_alignment
|
||
|
|
||
|
#endif // RK_ENGINE_CMP_MEMCPY_H
|