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