1de85bfc5SEd Schouten /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
38a36da99SPedro F. Giffuni *
4de85bfc5SEd Schouten * Copyright (c) 2012 Ed Schouten <ed@FreeBSD.org>
5de85bfc5SEd Schouten * All rights reserved.
6de85bfc5SEd Schouten *
7de85bfc5SEd Schouten * Redistribution and use in source and binary forms, with or without
8de85bfc5SEd Schouten * modification, are permitted provided that the following conditions
9de85bfc5SEd Schouten * are met:
10de85bfc5SEd Schouten * 1. Redistributions of source code must retain the above copyright
11de85bfc5SEd Schouten * notice, this list of conditions and the following disclaimer.
12de85bfc5SEd Schouten * 2. Redistributions in binary form must reproduce the above copyright
13de85bfc5SEd Schouten * notice, this list of conditions and the following disclaimer in the
14de85bfc5SEd Schouten * documentation and/or other materials provided with the distribution.
15de85bfc5SEd Schouten *
16de85bfc5SEd Schouten * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17de85bfc5SEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18de85bfc5SEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19de85bfc5SEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20de85bfc5SEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21de85bfc5SEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22de85bfc5SEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23de85bfc5SEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24de85bfc5SEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25de85bfc5SEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26de85bfc5SEd Schouten * SUCH DAMAGE.
27de85bfc5SEd Schouten */
28de85bfc5SEd Schouten
29de85bfc5SEd Schouten #include <sys/cdefs.h>
30de85bfc5SEd Schouten #include <sys/libkern.h>
31de85bfc5SEd Schouten #include <sys/limits.h>
32de85bfc5SEd Schouten #include <sys/param.h>
33de85bfc5SEd Schouten
34de85bfc5SEd Schouten /*
35de85bfc5SEd Schouten * memcchr(): find first character in buffer not matching `c'.
36de85bfc5SEd Schouten *
37de85bfc5SEd Schouten * This function performs the complement of memchr(). To provide decent
38de85bfc5SEd Schouten * performance, this function compares data from the buffer one word at
39de85bfc5SEd Schouten * a time.
40de85bfc5SEd Schouten *
41de85bfc5SEd Schouten * This code is inspired by libc's strlen(), written by Xin Li.
42de85bfc5SEd Schouten */
43de85bfc5SEd Schouten
44de85bfc5SEd Schouten #if LONG_BIT != 32 && LONG_BIT != 64
45de85bfc5SEd Schouten #error Unsupported word size
46de85bfc5SEd Schouten #endif
47de85bfc5SEd Schouten
48de85bfc5SEd Schouten #define LONGPTR_MASK (sizeof(long) - 1)
49de85bfc5SEd Schouten
50de85bfc5SEd Schouten #define TESTBYTE \
51de85bfc5SEd Schouten do { \
52de85bfc5SEd Schouten if (*p != (unsigned char)c) \
53de85bfc5SEd Schouten goto done; \
54de85bfc5SEd Schouten p++; \
55de85bfc5SEd Schouten } while (0)
56de85bfc5SEd Schouten
57de85bfc5SEd Schouten void *
memcchr(const void * begin,int c,size_t n)58de85bfc5SEd Schouten memcchr(const void *begin, int c, size_t n)
59de85bfc5SEd Schouten {
60de85bfc5SEd Schouten const unsigned long *lp;
61de85bfc5SEd Schouten const unsigned char *p, *end;
62de85bfc5SEd Schouten unsigned long word;
63de85bfc5SEd Schouten
64de85bfc5SEd Schouten /* Four or eight repetitions of `c'. */
65de85bfc5SEd Schouten word = (unsigned char)c;
66de85bfc5SEd Schouten word |= word << 8;
67de85bfc5SEd Schouten word |= word << 16;
68de85bfc5SEd Schouten #if LONG_BIT >= 64
69de85bfc5SEd Schouten word |= word << 32;
70de85bfc5SEd Schouten #endif
71de85bfc5SEd Schouten
72de85bfc5SEd Schouten /* Don't perform memory I/O when passing a zero-length buffer. */
73de85bfc5SEd Schouten if (n == 0)
74de85bfc5SEd Schouten return (NULL);
75de85bfc5SEd Schouten
76de85bfc5SEd Schouten /*
77de85bfc5SEd Schouten * First determine whether there is a character unequal to `c'
78de85bfc5SEd Schouten * in the first word. As this word may contain bytes before
79de85bfc5SEd Schouten * `begin', we may execute this loop spuriously.
80de85bfc5SEd Schouten */
81de85bfc5SEd Schouten lp = (const unsigned long *)((uintptr_t)begin & ~LONGPTR_MASK);
82de85bfc5SEd Schouten end = (const unsigned char *)begin + n;
83de85bfc5SEd Schouten if (*lp++ != word)
84de85bfc5SEd Schouten for (p = begin; p < (const unsigned char *)lp;)
85de85bfc5SEd Schouten TESTBYTE;
86de85bfc5SEd Schouten
87de85bfc5SEd Schouten /* Now compare the data one word at a time. */
88de85bfc5SEd Schouten for (; (const unsigned char *)lp < end; lp++) {
89de85bfc5SEd Schouten if (*lp != word) {
90de85bfc5SEd Schouten p = (const unsigned char *)lp;
91de85bfc5SEd Schouten TESTBYTE;
92de85bfc5SEd Schouten TESTBYTE;
93de85bfc5SEd Schouten TESTBYTE;
94de85bfc5SEd Schouten #if LONG_BIT >= 64
95de85bfc5SEd Schouten TESTBYTE;
96de85bfc5SEd Schouten TESTBYTE;
97de85bfc5SEd Schouten TESTBYTE;
98de85bfc5SEd Schouten TESTBYTE;
99de85bfc5SEd Schouten #endif
100de85bfc5SEd Schouten goto done;
101de85bfc5SEd Schouten }
102de85bfc5SEd Schouten }
103de85bfc5SEd Schouten
104de85bfc5SEd Schouten return (NULL);
105de85bfc5SEd Schouten
106de85bfc5SEd Schouten done:
107de85bfc5SEd Schouten /*
108de85bfc5SEd Schouten * If the end of the buffer is not word aligned, the previous
109de85bfc5SEd Schouten * loops may obtain an address that's beyond the end of the
110de85bfc5SEd Schouten * buffer.
111de85bfc5SEd Schouten */
112de85bfc5SEd Schouten if (p < end)
113de85bfc5SEd Schouten return (__DECONST(void *, p));
114de85bfc5SEd Schouten return (NULL);
115de85bfc5SEd Schouten }
116