// 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 .
#ifndef RK_ENGINE_CMP_MEMCPY_H
#define RK_ENGINE_CMP_MEMCPY_H
#include "types.hpp"
template
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
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
bool rk_cmp_memcpy(
void * const __restrict _dst,
void const * const __restrict _src,
unsigned const size);
template<>
bool rk_cmp_memcpy(
void * const __restrict _dst,
void const * const __restrict _src,
unsigned const size) {
#ifndef RK_CMP_MEMCPY_UNALIGNED
unsigned const alignment = reinterpret_cast(_dst) | reinterpret_cast(_src);
#endif
if (_rk_size_and_alignment(rk_ullong)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (_rk_size_and_alignment(rk_ulong)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (_rk_size_and_alignment(rk_uint)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (_rk_size_and_alignment(rk_ushort)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (size > 0) {
return _rk_cmp_memcpy_small(_dst, _src, size);
}
return false;
}
template<>
bool rk_cmp_memcpy(
void * const __restrict _dst,
void const * const __restrict _src,
unsigned const size) {
#ifndef RK_CMP_MEMCPY_UNALIGNED
unsigned const alignment = reinterpret_cast(_dst) | reinterpret_cast(_src);
#endif
if (_rk_size_and_alignment(rk_ullong)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (_rk_size_and_alignment(rk_ulong)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (_rk_size_and_alignment(rk_uint)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (size > 0) {
return _rk_cmp_memcpy_small(_dst, _src, size);
}
return false;
}
template<>
bool rk_cmp_memcpy(
void * const __restrict _dst,
void const * const __restrict _src,
unsigned const size) {
#ifndef RK_CMP_MEMCPY_UNALIGNED
unsigned const alignment = reinterpret_cast(_dst) | reinterpret_cast(_src);
#endif
if (_rk_size_and_alignment(rk_ullong)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (_rk_size_and_alignment(rk_ulong)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (size > 0) {
return _rk_cmp_memcpy_small(_dst, _src, size);
}
return false;
}
template<>
bool rk_cmp_memcpy(
void * const __restrict _dst,
void const * const __restrict _src,
unsigned const size) {
#ifndef RK_CMP_MEMCPY_UNALIGNED
unsigned const alignment = reinterpret_cast(_dst) | reinterpret_cast(_src);
#endif
if (_rk_size_and_alignment(rk_ullong)) {
return _rk_cmp_memcpy_big(_dst, _src, size);
}
if (size > 0) {
return _rk_cmp_memcpy_small(_dst, _src, size);
}
return false;
}
template<>
bool rk_cmp_memcpy(
void * const __restrict _dst,
void const * const __restrict _src,
unsigned const size) {
if (size > 0) {
return _rk_cmp_memcpy_small(_dst, _src, size);
}
return false;
}
#undef _rk_size_and_alignment
#endif // RK_ENGINE_CMP_MEMCPY_H