the comparison must take place in the address space model as an integer type, since comparing pointers that are not pointing into the same array is undefined. the subsequent d<s comparison however is valid, because it's only reached in the case where the source and dest overlap, in which case they are necessarily pointing to parts of the same array. to make the comparison, use an unsigned range check for dist(s,d)>=n, algebraically !(-n<s-d<n). subtracting n yields !(-2*n<s-d-n<0), which mapped into unsigned modular arithmetic is !(-2*n<s-d-n) or rather -2*n>=s-d-n.
37 lines
749 B
C
37 lines
749 B
C
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#define WT size_t
|
|
#define WS (sizeof(WT))
|
|
|
|
void *memmove(void *dest, const void *src, size_t n)
|
|
{
|
|
char *d = dest;
|
|
const char *s = src;
|
|
|
|
if (d==s) return d;
|
|
if ((uintptr_t)s-(uintptr_t)d-n <= -2*n) return memcpy(d, s, n);
|
|
|
|
if (d<s) {
|
|
if ((uintptr_t)s % WS == (uintptr_t)d % WS) {
|
|
while ((uintptr_t)d % WS) {
|
|
if (!n--) return dest;
|
|
*d++ = *s++;
|
|
}
|
|
for (; n>=WS; n-=WS, d+=WS, s+=WS) *(WT *)d = *(WT *)s;
|
|
}
|
|
for (; n; n--) *d++ = *s++;
|
|
} else {
|
|
if ((uintptr_t)s % WS == (uintptr_t)d % WS) {
|
|
while ((uintptr_t)(d+n) % WS) {
|
|
if (!n--) return dest;
|
|
d[n] = s[n];
|
|
}
|
|
while (n>=WS) n-=WS, *(WT *)(d+n) = *(WT *)(s+n);
|
|
}
|
|
while (n) n--, d[n] = s[n];
|
|
}
|
|
|
|
return dest;
|
|
}
|