1#include <string.h>
2
3#include <limits.h>
4#include <zircon/compiler.h>
5#include <stdint.h>
6
7#define ALIGN (sizeof(size_t) - 1)
8#define ONES ((size_t)-1 / UCHAR_MAX)
9#define HIGHS (ONES * (UCHAR_MAX / 2 + 1))
10#define HASZERO(x) (((x)-ONES) & ~(x)&HIGHS)
11
12void* memccpy(void* restrict dest, const void* restrict src, int c, size_t n) {
13    unsigned char* d = dest;
14    const unsigned char* s = src;
15
16    c = (unsigned char)c;
17    // This reads past the end of the string, which is usually OK since
18    // it won't cross a page boundary.  But under ASan, even one byte
19    // past the actual end is diagnosed.
20    if (!__has_feature(address_sanitizer) &&
21        ((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
22        for (; ((uintptr_t)s & ALIGN) && n && (*d = *s) != c; n--, s++, d++)
23            ;
24        if ((uintptr_t)s & ALIGN)
25            goto tail;
26        size_t k = ONES * c;
27        size_t* wd = (void*)d;
28        const size_t* ws = (const void*)s;
29        for (; n >= sizeof(size_t) && !HASZERO(*ws ^ k); n -= sizeof(size_t), ws++, wd++)
30            *wd = *ws;
31        d = (void*)wd;
32        s = (const void*)ws;
33    }
34    for (; n && (*d = *s) != c; n--, s++, d++)
35        ;
36tail:
37    if (*s == c)
38        return d + 1;
39    return 0;
40}
41