memmove - AugustinLopez/libft GitHub Wiki
From The Open Group Base Specifications issue 7, 2018:
#include <string.h>
void *memmove(void *s1, const void *s2, size_t n);
- The memmove() function shall copy n bytes from the object pointed to by s2 into the object pointed to by s1.
- Copying takes place as if the n bytes from the object pointed to by s2 are first copied into a temporary array of n bytes that does not overlap the objects pointed to by s1 and s2, and then the n bytes from the temporary array are copied into the object pointed to by s1.
- The memmove() function shall return s1; no return value is reserved to indicate an error.
- No errors are defined.
Relevant wiki: memcpy.
Relevant concepts: Operator precedence, type casting, const keyword.
#include "libft.h"
#include <string.h>
void *ft_memmove(void *s1, const void *s2, size_t n)
{
unsigned char *cs1;
const unsigned char *cs2;
if (s1 < s2)
return (ft_memcpy(s1, s2, n));
if (!n || (s1 == s2))
return (s1);
cs1 = (unsigned char *)s1;
cs2 = (const unsigned char *)s2;
while (n--)
cs1[n] = cs2[n];
return (s1);
}
For more information, please refer to the Optimization Concepts page.
#include "libft.h"
#include <string.h>
#include <stdint.h>
void *ft_memmove(void *s1, const void *s2, size_t n)
{
unsigned char *cs1;
const unsigned char *cs2;
uint64_t *lls1;
const uint64_t *lls2;
if (s1 < s2)
return (ft_memcpy(s1, s2, n));
else if (!n || (s1 == s2))
return (s1);
cs1 = (unsigned char *)s1 + n - 1;
cs2 = (const unsigned char *)s2 + n - 1;
if ((n >= 15) && (((uintptr_t)s1 & 0x7) == ((uintptr_t)s2 & 0x7)))
{
while (((uintptr_t)cs1 & 0x7))
{
*cs1-- = *cs2--;
--n;
}
*cs1 = *cs2;
lls1 = (uint64_t *)cs1 - 1;
lls2 = (const uint64_t *)cs2 - 1;
while (n >= 8)
{
*lls1-- = *lls2--;
n -= 8;
}
if (n)
{
cs1 = (unsigned char *)lls1 - 1;
cs2 = (const unsigned char *)lls2 - 1;
}
}
while (n--)
*cs1-- = *cs2--;
return (s1);
}
- Results are a percentage of the performance against a glibc memmove [ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27].
- Compiler is gcc [(Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0].
- for each size the test runtime is 5 seconds.
- Memory is aligned.
| Size\flag | -O3 -fno-builtin | -O2 | -Os | (none) |
|---|---|---|---|---|
| 1 | 99% | 99% | 101% | 100% |
| 10 | 98% | 99% | 99% | 98% |
| 100 | 98% | 98% | 95% | 84% |
| 1K | 78% | 78% | 75% | 35% |
| 10K | 31% | 30% | 26% | 6% |
| 100K | 14% | 14% | 12% | 2% |
| 1M | 12% | 13% | 12% | 2% |
| Size\flag | -O3 -fno-builtin | -O2 | -Os | (none) |
|---|---|---|---|---|
| 1 | 99% | 100% | 99% | 98% |
| 10 | 98% | 97% | 99% | 97% |
| 100 | 98% | 99% | 100% | 96% |
| 1K | 96% | 97% | 95% | 81% |
| 10K | 93% | 84% | 82% | 38% |
| 100K | 100% | 83% | 83% | 19% |
| 1M | 83% | 75% | 75% | 19% |
# include <time.h>
# include <string.h>
# include <stdlib.h>
size_t memmove_speed_test(int len, int second, void *(mem)(void *, const void *, size_t))
{
clock_t chrono = 0;
clock_t start = 0;
size_t i = 0;
void *dst;
void *src1;
void *src2;
void *tmp;
dst = malloc(len);
src1 = malloc(len);
src2 = malloc(len);
if (!dst || !src1 || !src2)
exit(1);
if (dst < src1)
{
tmp = dst;
dst = src1;
src1 = tmp;
}
if (dst < src2)
{
tmp = dst;
dst = src2;
src2 = tmp;
}
memset(src1, 0xff, len);
memset(src2, 0, len);
memset(dst, 0, len);
start = clock();
while (chrono < second * CLOCKS_PER_SEC)
{
if (i % 2)
mem(dst, src1, len);
else
mem(dst, src2, len);
i++;
chrono = clock() - start;
}
free(dst);
free(src1);
free(src2);
return (i);
}