memchr - AugustinLopez/libft GitHub Wiki
From The Open Group Base Specifications issue 7, 2018:
#include <string.h>
void *memchr(const void *s, int c, size_t n);
- The memchr() function shall locate the first occurrence of c (converted to an unsigned char) in the initial n bytes (each interpreted as unsigned char) pointed to by s.
- Implementations shall behave as if they read the memory byte by byte from the beginning of the bytes pointed to by s and stop at the first occurrence of c (if it is found in the initial n bytes).
- The memchr() function shall return a pointer to the located byte, or a null pointer if the byte is not found.
- No errors are defined.
Relevant concepts: Operator precedence, type casting, const keyword
#include <string.h>
void *ft_memchr(const void *s, int c, size_t n)
{
const unsigned char *pc;
pc = (const unsigned char *)s;
while (n--)
{
if (*pc == (unsigned char)c)
return ((void *)pc);
++pc;
}
return (NULL);
}
For more information, please refer to the Optimization Concepts page.
#include <string.h>
#include <stdint.h>
void *memchr(const void *s, int c, size_t n)
{
const unsigned char *pc;
uint64_t *pll;
uint64_t one_each_byte;
uint64_t c_each_byte;
uint64_t zero_mask;
pc = (const unsigned char *)s;
while ((uintptr_t)pc & 0x7)
{
if (*pc == (unsigned char)c)
return ((void *)pc);
++pc;
if (!--n)
return (NULL);
}
if (n >= 8)
{
pll = (uint64_t *)pc;
one_each_byte = 0x0101010101010101L;
c_each_byte = c | (c << 8);
c_each_byte |= c_each_byte << 16;
c_each_byte |= c_each_byte << 32;
while (*n >= 8)
{
zero_mask = *pll ^ c_each_byte;
if (((zero_mask - one_each_byte) & ~zero_mask) & (one_each_byte << 7))
break ;
pll++;
*n -= 8;
}
pc = (const unsigned char *)pll;
}
while (n--)
{
if (*pc == (unsigned char)c)
return ((void *)pc);
++pc;
}
return (NULL);
}
- Results are a percentage of the performance against a glibc memchr [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.
| Size\flag | -O3 -fno-builtin | -O2 | -Os | (none) |
|---|---|---|---|---|
| 1 | 100% | 101% | 100% | 99% |
| 10 | 99% | 101% | 100% | 99% |
| 100 | 96% | 96% | 95% | 87% |
| 1K | 80% | 81% | 74% | 40% |
| 10K | 32% | 32% | 24% | 7% |
| 100K | 9% | 9% | 6% | 1% |
| 1M | 8% | 9% | 6% | 1% |
| Size\flag | -O3 -fno-builtin | -O2 | -Os | (none) |
|---|---|---|---|---|
| 1 | 99% | 99% | 101% | 99% |
| 10 | 100% | 100% | 101% | 99% |
| 100 | 99% | 99% | 99% | 97% |
| 1K | 93% | 92% | 92% | 77% |
| 10K | 62% | 61% | 62% | 28% |
| 100K | 25% | 25% | 26% | 7% |
| 1M | 26% | 26% | 27% | 7% |
# include <time.h>
# include <string.h>
# include <stdlib.h>
size_t memchr_speed_test(int len, int second, void *(mem)(const void *, int, size_t))
{
clock_t chrono = 0;
clock_t start = 0;
size_t i = 0;
void *buff;
if (!(buff = malloc(len + 1)))
exit(1);
memset(buff, 0, len + 1);
((char *)buff)[len] = 1;
start = clock();
while (chrono < second * CLOCKS_PER_SEC)
{
mem(buff, 1, len + 1);
i++;
chrono = clock() - start;
}
free(buff);
return (i);
}
- std::find() and memchr() Optimizations : Georg Sauthoff, September 2016.