memcchr.c revision 229198
1229198Sed/*- 2229198Sed * Copyright (c) 2012 Ed Schouten <ed@FreeBSD.org> 3229198Sed * All rights reserved. 4229198Sed * 5229198Sed * Redistribution and use in source and binary forms, with or without 6229198Sed * modification, are permitted provided that the following conditions 7229198Sed * are met: 8229198Sed * 1. Redistributions of source code must retain the above copyright 9229198Sed * notice, this list of conditions and the following disclaimer. 10229198Sed * 2. Redistributions in binary form must reproduce the above copyright 11229198Sed * notice, this list of conditions and the following disclaimer in the 12229198Sed * documentation and/or other materials provided with the distribution. 13229198Sed * 14229198Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15229198Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16229198Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17229198Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18229198Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19229198Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20229198Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21229198Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22229198Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23229198Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24229198Sed * SUCH DAMAGE. 25229198Sed */ 26229198Sed 27229198Sed#include <sys/cdefs.h> 28229198Sed__FBSDID("$FreeBSD: head/sys/libkern/memcchr.c 229198 2012-01-01 20:26:11Z ed $"); 29229198Sed 30229198Sed#include <sys/libkern.h> 31229198Sed#include <sys/limits.h> 32229198Sed#include <sys/param.h> 33229198Sed 34229198Sed/* 35229198Sed * memcchr(): find first character in buffer not matching `c'. 36229198Sed * 37229198Sed * This function performs the complement of memchr(). To provide decent 38229198Sed * performance, this function compares data from the buffer one word at 39229198Sed * a time. 40229198Sed * 41229198Sed * This code is inspired by libc's strlen(), written by Xin Li. 42229198Sed */ 43229198Sed 44229198Sed#if LONG_BIT != 32 && LONG_BIT != 64 45229198Sed#error Unsupported word size 46229198Sed#endif 47229198Sed 48229198Sed#define LONGPTR_MASK (sizeof(long) - 1) 49229198Sed 50229198Sed#define TESTBYTE \ 51229198Sed do { \ 52229198Sed if (*p != (unsigned char)c) \ 53229198Sed goto done; \ 54229198Sed p++; \ 55229198Sed } while (0) 56229198Sed 57229198Sedvoid * 58229198Sedmemcchr(const void *begin, int c, size_t n) 59229198Sed{ 60229198Sed const unsigned long *lp; 61229198Sed const unsigned char *p, *end; 62229198Sed unsigned long word; 63229198Sed 64229198Sed /* Four or eight repetitions of `c'. */ 65229198Sed word = (unsigned char)c; 66229198Sed word |= word << 8; 67229198Sed word |= word << 16; 68229198Sed#if LONG_BIT >= 64 69229198Sed word |= word << 32; 70229198Sed#endif 71229198Sed 72229198Sed /* Don't perform memory I/O when passing a zero-length buffer. */ 73229198Sed if (n == 0) 74229198Sed return (NULL); 75229198Sed 76229198Sed /* 77229198Sed * First determine whether there is a character unequal to `c' 78229198Sed * in the first word. As this word may contain bytes before 79229198Sed * `begin', we may execute this loop spuriously. 80229198Sed */ 81229198Sed lp = (const unsigned long *)((uintptr_t)begin & ~LONGPTR_MASK); 82229198Sed end = (const unsigned char *)begin + n; 83229198Sed if (*lp++ != word) 84229198Sed for (p = begin; p < (const unsigned char *)lp;) 85229198Sed TESTBYTE; 86229198Sed 87229198Sed /* Now compare the data one word at a time. */ 88229198Sed for (; (const unsigned char *)lp < end; lp++) { 89229198Sed if (*lp != word) { 90229198Sed p = (const unsigned char *)lp; 91229198Sed TESTBYTE; 92229198Sed TESTBYTE; 93229198Sed TESTBYTE; 94229198Sed#if LONG_BIT >= 64 95229198Sed TESTBYTE; 96229198Sed TESTBYTE; 97229198Sed TESTBYTE; 98229198Sed TESTBYTE; 99229198Sed#endif 100229198Sed goto done; 101229198Sed } 102229198Sed } 103229198Sed 104229198Sed return (NULL); 105229198Sed 106229198Seddone: 107229198Sed /* 108229198Sed * If the end of the buffer is not word aligned, the previous 109229198Sed * loops may obtain an address that's beyond the end of the 110229198Sed * buffer. 111229198Sed */ 112229198Sed if (p < end) 113229198Sed return (__DECONST(void *, p)); 114229198Sed return (NULL); 115229198Sed} 116