diff options
author | ed <ed@FreeBSD.org> | 2012-01-01 20:26:11 +0000 |
---|---|---|
committer | ed <ed@FreeBSD.org> | 2012-01-01 20:26:11 +0000 |
commit | a201da71788983b3f0445aa46bca32751fc7393c (patch) | |
tree | af6bd36dd5b255501e8018e450b5f00a332c52cb | |
parent | 4a643207b240e975c07808e969d7545d1d8c0b31 (diff) | |
download | FreeBSD-src-a201da71788983b3f0445aa46bca32751fc7393c.zip FreeBSD-src-a201da71788983b3f0445aa46bca32751fc7393c.tar.gz |
Introducing memcchr(3).
It seems two of the file system drivers we have in the tree, namely ufs
and ext3, use a function called `skpc()'. The meaning of this function
does not seem to be documented in FreeBSD, but it turns out one needs to
be a VAX programmer to understand what it does.
SPKC is an instruction on the VAX that does the opposite of memchr(). It
searches for the non-equal character. Add a new function called
memcchr() to the tree that has the following advantages over skpc():
- It has a name that makes more sense than skpc(). Just like strcspn()
matches the complement of strspn(), memcchr() is the complement of
memchr().
- It is faster than skpc(). Similar to our strlen() in libc, it compares
entire words, instead of single bytes. It seems that for this routine
this yields a sixfold performance increase on amd64.
- It has a man page.
-rw-r--r-- | share/man/man9/memcchr.3 | 59 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/libkern/memcchr.c | 115 | ||||
-rw-r--r-- | sys/sys/libkern.h | 1 |
4 files changed, 176 insertions, 0 deletions
diff --git a/share/man/man9/memcchr.3 b/share/man/man9/memcchr.3 new file mode 100644 index 0000000..a3ade21 --- /dev/null +++ b/share/man/man9/memcchr.3 @@ -0,0 +1,59 @@ +.\" Copyright (c) 2012 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd January 1, 2012 +.Dt MEMCCHR 9 +.Os +.Sh NAME +.Nm memcchr +.Nd locate the complement of a byte in byte string +.Sh SYNOPSIS +.In sys/libkern.h +.Ft void * +.Fn memcchr "const void *b" "int c" "size_t len" +.Sh DESCRIPTION +The +.Fn memcchr +function locates the first occurrence of a byte unequal to +.Fa c +(converted to an +.Vt "unsigned char" ) +in string +.Fa b . +.Sh RETURN VALUES +The +.Fn memcchr +function return a pointer to the byte located, or NULL if no such byte +exists within +.Fa len +bytes. +.Sh SEE ALSO +.Xr memchr 3 +.Sh HISTORY +The +.Fn memcchr +function first appeared in +.Fx 10.0 . diff --git a/sys/conf/files b/sys/conf/files index 2f8b5f6..871921c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2557,6 +2557,7 @@ libkern/inet_ntoa.c standard libkern/inet_ntop.c standard libkern/inet_pton.c standard libkern/mcount.c optional profiling-routine +libkern/memcchr.c standard libkern/memcmp.c standard libkern/qsort.c standard libkern/qsort_r.c standard diff --git a/sys/libkern/memcchr.c b/sys/libkern/memcchr.c new file mode 100644 index 0000000..eebb23a --- /dev/null +++ b/sys/libkern/memcchr.c @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 2012 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/libkern.h> +#include <sys/limits.h> +#include <sys/param.h> + +/* + * memcchr(): find first character in buffer not matching `c'. + * + * This function performs the complement of memchr(). To provide decent + * performance, this function compares data from the buffer one word at + * a time. + * + * This code is inspired by libc's strlen(), written by Xin Li. + */ + +#if LONG_BIT != 32 && LONG_BIT != 64 +#error Unsupported word size +#endif + +#define LONGPTR_MASK (sizeof(long) - 1) + +#define TESTBYTE \ + do { \ + if (*p != (unsigned char)c) \ + goto done; \ + p++; \ + } while (0) + +void * +memcchr(const void *begin, int c, size_t n) +{ + const unsigned long *lp; + const unsigned char *p, *end; + unsigned long word; + + /* Four or eight repetitions of `c'. */ + word = (unsigned char)c; + word |= word << 8; + word |= word << 16; +#if LONG_BIT >= 64 + word |= word << 32; +#endif + + /* Don't perform memory I/O when passing a zero-length buffer. */ + if (n == 0) + return (NULL); + + /* + * First determine whether there is a character unequal to `c' + * in the first word. As this word may contain bytes before + * `begin', we may execute this loop spuriously. + */ + lp = (const unsigned long *)((uintptr_t)begin & ~LONGPTR_MASK); + end = (const unsigned char *)begin + n; + if (*lp++ != word) + for (p = begin; p < (const unsigned char *)lp;) + TESTBYTE; + + /* Now compare the data one word at a time. */ + for (; (const unsigned char *)lp < end; lp++) { + if (*lp != word) { + p = (const unsigned char *)lp; + TESTBYTE; + TESTBYTE; + TESTBYTE; +#if LONG_BIT >= 64 + TESTBYTE; + TESTBYTE; + TESTBYTE; + TESTBYTE; +#endif + goto done; + } + } + + return (NULL); + +done: + /* + * If the end of the buffer is not word aligned, the previous + * loops may obtain an address that's beyond the end of the + * buffer. + */ + if (p < end) + return (__DECONST(void *, p)); + return (NULL); +} diff --git a/sys/sys/libkern.h b/sys/sys/libkern.h index aa53fb7..0e525de 100644 --- a/sys/sys/libkern.h +++ b/sys/sys/libkern.h @@ -92,6 +92,7 @@ int flsl(long); int fnmatch(const char *, const char *, int); int locc(int, char *, u_int); void *memchr(const void *s, int c, size_t n); +void *memcchr(const void *s, int c, size_t n); int memcmp(const void *b1, const void *b2, size_t len); void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); |