xref: /freebsd-src/sys/libkern/memcchr.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
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