Tune by using memchr and memrchr.

* .bzrignore: Add string.h.
* admin/merge-gnulib (GNULIB_MODULES): Add memrchr.
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
* lib/memrchr.c, lib/string.in.h, m4/memrchr.m4, m4/string_h.m4:
New files, from gnulib.
* src/doc.c (Fsnarf_documentation):
* src/fileio.c (Fsubstitute_in_file_name):
* src/search.c (find_newline, scan_newline):
* src/xdisp.c (pos_visible_p, display_count_lines):
Use memchr and memrchr rather than scanning byte-by-byte.
* src/search.c (find_newline): Rename from scan_buffer.
Omit first arg TARGET, as it's always '\n'.  All callers changed.
This commit is contained in:
Paul Eggert 2013-02-11 15:37:18 -08:00
parent 71d4202f20
commit a84b7c5334
17 changed files with 1622 additions and 163 deletions

View file

@ -1,5 +1,11 @@
2013-02-11 Paul Eggert <eggert@cs.ucla.edu>
Tune by using memchr and memrchr.
* .bzrignore: Add string.h.
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
* lib/memrchr.c, lib/string.in.h, m4/memrchr.m4, m4/string_h.m4:
New files, from gnulib.
Merge from gnulib, incorporating:
2013-02-11 unsetenv etc.: port to Solaris 11 + GNU Emacs
2013-02-09 secure_getenv: fix C++ declaration typo

View file

@ -1,3 +1,8 @@
2013-02-11 Paul Eggert <eggert@cs.ucla.edu>
Tune by using memchr and memrchr.
* merge-gnulib (GNULIB_MODULES): Add memrchr.
2013-02-01 Paul Eggert <eggert@cs.ucla.edu>
Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539).

View file

@ -31,7 +31,8 @@ GNULIB_MODULES='
dtoastr dtotimespec dup2 environ execinfo faccessat
fcntl-h fdopendir filemode fstatat getloadavg getopt-gnu gettime gettimeofday
ignore-value intprops largefile lstat
manywarnings mktime pselect pthread_sigmask putenv readlink readlinkat
manywarnings memrchr mktime
pselect pthread_sigmask putenv readlink readlinkat
sig2str socklen stat-time stdalign stdarg stdbool stdio
strftime strtoimax strtoumax symlink sys_stat
sys_time time timer-time timespec-add timespec-sub unsetenv utimens

View file

@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=dup --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl-h fdopendir filemode fstatat getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask putenv readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=dup --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl-h fdopendir filemode fstatat getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings memrchr mktime pselect pthread_sigmask putenv readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings
MOSTLYCLEANFILES += core *.stackdump
@ -480,6 +480,15 @@ EXTRA_libgnu_a_SOURCES += lstat.c
## end gnulib module lstat
## begin gnulib module memrchr
EXTRA_DIST += memrchr.c
EXTRA_libgnu_a_SOURCES += memrchr.c
## end gnulib module memrchr
## begin gnulib module mktime
@ -1105,6 +1114,106 @@ EXTRA_DIST += strftime.h
## end gnulib module strftime
## begin gnulib module string
BUILT_SOURCES += string.h
# We need the following in order to create <string.h> when the system
# doesn't have one that works with the given compiler.
string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
$(AM_V_GEN)rm -f $@-t $@ && \
{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
sed -e 's|@''GUARD_PREFIX''@|GL|g' \
-e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
-e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
-e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
-e 's|@''NEXT_STRING_H''@|$(NEXT_STRING_H)|g' \
-e 's/@''GNULIB_FFSL''@/$(GNULIB_FFSL)/g' \
-e 's/@''GNULIB_FFSLL''@/$(GNULIB_FFSLL)/g' \
-e 's/@''GNULIB_MBSLEN''@/$(GNULIB_MBSLEN)/g' \
-e 's/@''GNULIB_MBSNLEN''@/$(GNULIB_MBSNLEN)/g' \
-e 's/@''GNULIB_MBSCHR''@/$(GNULIB_MBSCHR)/g' \
-e 's/@''GNULIB_MBSRCHR''@/$(GNULIB_MBSRCHR)/g' \
-e 's/@''GNULIB_MBSSTR''@/$(GNULIB_MBSSTR)/g' \
-e 's/@''GNULIB_MBSCASECMP''@/$(GNULIB_MBSCASECMP)/g' \
-e 's/@''GNULIB_MBSNCASECMP''@/$(GNULIB_MBSNCASECMP)/g' \
-e 's/@''GNULIB_MBSPCASECMP''@/$(GNULIB_MBSPCASECMP)/g' \
-e 's/@''GNULIB_MBSCASESTR''@/$(GNULIB_MBSCASESTR)/g' \
-e 's/@''GNULIB_MBSCSPN''@/$(GNULIB_MBSCSPN)/g' \
-e 's/@''GNULIB_MBSPBRK''@/$(GNULIB_MBSPBRK)/g' \
-e 's/@''GNULIB_MBSSPN''@/$(GNULIB_MBSSPN)/g' \
-e 's/@''GNULIB_MBSSEP''@/$(GNULIB_MBSSEP)/g' \
-e 's/@''GNULIB_MBSTOK_R''@/$(GNULIB_MBSTOK_R)/g' \
-e 's/@''GNULIB_MEMCHR''@/$(GNULIB_MEMCHR)/g' \
-e 's/@''GNULIB_MEMMEM''@/$(GNULIB_MEMMEM)/g' \
-e 's/@''GNULIB_MEMPCPY''@/$(GNULIB_MEMPCPY)/g' \
-e 's/@''GNULIB_MEMRCHR''@/$(GNULIB_MEMRCHR)/g' \
-e 's/@''GNULIB_RAWMEMCHR''@/$(GNULIB_RAWMEMCHR)/g' \
-e 's/@''GNULIB_STPCPY''@/$(GNULIB_STPCPY)/g' \
-e 's/@''GNULIB_STPNCPY''@/$(GNULIB_STPNCPY)/g' \
-e 's/@''GNULIB_STRCHRNUL''@/$(GNULIB_STRCHRNUL)/g' \
-e 's/@''GNULIB_STRDUP''@/$(GNULIB_STRDUP)/g' \
-e 's/@''GNULIB_STRNCAT''@/$(GNULIB_STRNCAT)/g' \
-e 's/@''GNULIB_STRNDUP''@/$(GNULIB_STRNDUP)/g' \
-e 's/@''GNULIB_STRNLEN''@/$(GNULIB_STRNLEN)/g' \
-e 's/@''GNULIB_STRPBRK''@/$(GNULIB_STRPBRK)/g' \
-e 's/@''GNULIB_STRSEP''@/$(GNULIB_STRSEP)/g' \
-e 's/@''GNULIB_STRSTR''@/$(GNULIB_STRSTR)/g' \
-e 's/@''GNULIB_STRCASESTR''@/$(GNULIB_STRCASESTR)/g' \
-e 's/@''GNULIB_STRTOK_R''@/$(GNULIB_STRTOK_R)/g' \
-e 's/@''GNULIB_STRERROR''@/$(GNULIB_STRERROR)/g' \
-e 's/@''GNULIB_STRERROR_R''@/$(GNULIB_STRERROR_R)/g' \
-e 's/@''GNULIB_STRSIGNAL''@/$(GNULIB_STRSIGNAL)/g' \
-e 's/@''GNULIB_STRVERSCMP''@/$(GNULIB_STRVERSCMP)/g' \
< $(srcdir)/string.in.h | \
sed -e 's|@''HAVE_FFSL''@|$(HAVE_FFSL)|g' \
-e 's|@''HAVE_FFSLL''@|$(HAVE_FFSLL)|g' \
-e 's|@''HAVE_MBSLEN''@|$(HAVE_MBSLEN)|g' \
-e 's|@''HAVE_MEMCHR''@|$(HAVE_MEMCHR)|g' \
-e 's|@''HAVE_DECL_MEMMEM''@|$(HAVE_DECL_MEMMEM)|g' \
-e 's|@''HAVE_MEMPCPY''@|$(HAVE_MEMPCPY)|g' \
-e 's|@''HAVE_DECL_MEMRCHR''@|$(HAVE_DECL_MEMRCHR)|g' \
-e 's|@''HAVE_RAWMEMCHR''@|$(HAVE_RAWMEMCHR)|g' \
-e 's|@''HAVE_STPCPY''@|$(HAVE_STPCPY)|g' \
-e 's|@''HAVE_STPNCPY''@|$(HAVE_STPNCPY)|g' \
-e 's|@''HAVE_STRCHRNUL''@|$(HAVE_STRCHRNUL)|g' \
-e 's|@''HAVE_DECL_STRDUP''@|$(HAVE_DECL_STRDUP)|g' \
-e 's|@''HAVE_DECL_STRNDUP''@|$(HAVE_DECL_STRNDUP)|g' \
-e 's|@''HAVE_DECL_STRNLEN''@|$(HAVE_DECL_STRNLEN)|g' \
-e 's|@''HAVE_STRPBRK''@|$(HAVE_STRPBRK)|g' \
-e 's|@''HAVE_STRSEP''@|$(HAVE_STRSEP)|g' \
-e 's|@''HAVE_STRCASESTR''@|$(HAVE_STRCASESTR)|g' \
-e 's|@''HAVE_DECL_STRTOK_R''@|$(HAVE_DECL_STRTOK_R)|g' \
-e 's|@''HAVE_DECL_STRERROR_R''@|$(HAVE_DECL_STRERROR_R)|g' \
-e 's|@''HAVE_DECL_STRSIGNAL''@|$(HAVE_DECL_STRSIGNAL)|g' \
-e 's|@''HAVE_STRVERSCMP''@|$(HAVE_STRVERSCMP)|g' \
-e 's|@''REPLACE_STPNCPY''@|$(REPLACE_STPNCPY)|g' \
-e 's|@''REPLACE_MEMCHR''@|$(REPLACE_MEMCHR)|g' \
-e 's|@''REPLACE_MEMMEM''@|$(REPLACE_MEMMEM)|g' \
-e 's|@''REPLACE_STRCASESTR''@|$(REPLACE_STRCASESTR)|g' \
-e 's|@''REPLACE_STRCHRNUL''@|$(REPLACE_STRCHRNUL)|g' \
-e 's|@''REPLACE_STRDUP''@|$(REPLACE_STRDUP)|g' \
-e 's|@''REPLACE_STRSTR''@|$(REPLACE_STRSTR)|g' \
-e 's|@''REPLACE_STRERROR''@|$(REPLACE_STRERROR)|g' \
-e 's|@''REPLACE_STRERROR_R''@|$(REPLACE_STRERROR_R)|g' \
-e 's|@''REPLACE_STRNCAT''@|$(REPLACE_STRNCAT)|g' \
-e 's|@''REPLACE_STRNDUP''@|$(REPLACE_STRNDUP)|g' \
-e 's|@''REPLACE_STRNLEN''@|$(REPLACE_STRNLEN)|g' \
-e 's|@''REPLACE_STRSIGNAL''@|$(REPLACE_STRSIGNAL)|g' \
-e 's|@''REPLACE_STRTOK_R''@|$(REPLACE_STRTOK_R)|g' \
-e 's|@''UNDEFINE_STRTOK_R''@|$(UNDEFINE_STRTOK_R)|g' \
-e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
-e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
-e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)'; \
< $(srcdir)/string.in.h; \
} > $@-t && \
mv $@-t $@
MOSTLYCLEANFILES += string.h string.h-t
EXTRA_DIST += string.in.h
## end gnulib module string
## begin gnulib module strtoimax

161
lib/memrchr.c Normal file
View file

@ -0,0 +1,161 @@
/* memrchr -- find the last occurrence of a byte in a memory block
Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2013 Free Software
Foundation, Inc.
Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
with help from Dan Sahlin (dan@sics.se) and
commentary by Jim Blandy (jimb@ai.mit.edu);
adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
and implemented by Roland McGrath (roland@ai.mit.edu).
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#if defined _LIBC
# include <memcopy.h>
#else
# include <config.h>
# define reg_char char
#endif
#include <string.h>
#include <limits.h>
#undef __memrchr
#ifdef _LIBC
# undef memrchr
#endif
#ifndef weak_alias
# define __memrchr memrchr
#endif
/* Search no more than N bytes of S for C. */
void *
__memrchr (void const *s, int c_in, size_t n)
{
/* On 32-bit hardware, choosing longword to be a 32-bit unsigned
long instead of a 64-bit uintmax_t tends to give better
performance. On 64-bit hardware, unsigned long is generally 64
bits already. Change this typedef to experiment with
performance. */
typedef unsigned long int longword;
const unsigned char *char_ptr;
const longword *longword_ptr;
longword repeated_one;
longword repeated_c;
unsigned reg_char c;
c = (unsigned char) c_in;
/* Handle the last few bytes by reading one byte at a time.
Do this until CHAR_PTR is aligned on a longword boundary. */
for (char_ptr = (const unsigned char *) s + n;
n > 0 && (size_t) char_ptr % sizeof (longword) != 0;
--n)
if (*--char_ptr == c)
return (void *) char_ptr;
longword_ptr = (const longword *) char_ptr;
/* All these elucidatory comments refer to 4-byte longwords,
but the theory applies equally well to any size longwords. */
/* Compute auxiliary longword values:
repeated_one is a value which has a 1 in every byte.
repeated_c has c in every byte. */
repeated_one = 0x01010101;
repeated_c = c | (c << 8);
repeated_c |= repeated_c << 16;
if (0xffffffffU < (longword) -1)
{
repeated_one |= repeated_one << 31 << 1;
repeated_c |= repeated_c << 31 << 1;
if (8 < sizeof (longword))
{
size_t i;
for (i = 64; i < sizeof (longword) * 8; i *= 2)
{
repeated_one |= repeated_one << i;
repeated_c |= repeated_c << i;
}
}
}
/* Instead of the traditional loop which tests each byte, we will test a
longword at a time. The tricky part is testing if *any of the four*
bytes in the longword in question are equal to c. We first use an xor
with repeated_c. This reduces the task to testing whether *any of the
four* bytes in longword1 is zero.
We compute tmp =
((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
That is, we perform the following operations:
1. Subtract repeated_one.
2. & ~longword1.
3. & a mask consisting of 0x80 in every byte.
Consider what happens in each byte:
- If a byte of longword1 is zero, step 1 and 2 transform it into 0xff,
and step 3 transforms it into 0x80. A carry can also be propagated
to more significant bytes.
- If a byte of longword1 is nonzero, let its lowest 1 bit be at
position k (0 <= k <= 7); so the lowest k bits are 0. After step 1,
the byte ends in a single bit of value 0 and k bits of value 1.
After step 2, the result is just k bits of value 1: 2^k - 1. After
step 3, the result is 0. And no carry is produced.
So, if longword1 has only non-zero bytes, tmp is zero.
Whereas if longword1 has a zero byte, call j the position of the least
significant zero byte. Then the result has a zero at positions 0, ...,
j-1 and a 0x80 at position j. We cannot predict the result at the more
significant bytes (positions j+1..3), but it does not matter since we
already have a non-zero bit at position 8*j+7.
So, the test whether any byte in longword1 is zero is equivalent to
testing whether tmp is nonzero. */
while (n >= sizeof (longword))
{
longword longword1 = *--longword_ptr ^ repeated_c;
if ((((longword1 - repeated_one) & ~longword1)
& (repeated_one << 7)) != 0)
{
longword_ptr++;
break;
}
n -= sizeof (longword);
}
char_ptr = (const unsigned char *) longword_ptr;
/* At this point, we know that either n < sizeof (longword), or one of the
sizeof (longword) bytes starting at char_ptr is == c. On little-endian
machines, we could determine the first such byte without any further
memory accesses, just by looking at the tmp result from the last loop
iteration. But this does not work on big-endian machines. Choose code
that works in both cases. */
while (n-- > 0)
{
if (*--char_ptr == c)
return (void *) char_ptr;
}
return NULL;
}
#ifdef weak_alias
weak_alias (__memrchr, memrchr)
#endif

1029
lib/string.in.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -83,6 +83,7 @@ AC_DEFUN([gl_EARLY],
AC_REQUIRE([AC_SYS_LARGEFILE])
# Code from module lstat:
# Code from module manywarnings:
# Code from module memrchr:
# Code from module mktime:
# Code from module multiarch:
# Code from module nocrash:
@ -117,6 +118,7 @@ AC_DEFUN([gl_EARLY],
# Code from module stdio:
# Code from module stdlib:
# Code from module strftime:
# Code from module string:
# Code from module strtoimax:
# Code from module strtoll:
# Code from module strtoull:
@ -242,6 +244,12 @@ AC_DEFUN([gl_INIT],
gl_PREREQ_LSTAT
fi
gl_SYS_STAT_MODULE_INDICATOR([lstat])
gl_FUNC_MEMRCHR
if test $ac_cv_func_memrchr = no; then
AC_LIBOBJ([memrchr])
gl_PREREQ_MEMRCHR
fi
gl_STRING_MODULE_INDICATOR([memrchr])
gl_FUNC_MKTIME
if test $REPLACE_MKTIME = 1; then
AC_LIBOBJ([mktime])
@ -294,6 +302,7 @@ AC_DEFUN([gl_INIT],
gl_STDIO_H
gl_STDLIB_H
gl_FUNC_GNU_STRFTIME
gl_HEADER_STRING_H
gl_FUNC_STRTOIMAX
if test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; then
AC_LIBOBJ([strtoimax])
@ -757,6 +766,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/lstat.c
lib/md5.c
lib/md5.h
lib/memrchr.c
lib/mktime-internal.h
lib/mktime.c
lib/openat-priv.h
@ -790,6 +800,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/stdlib.in.h
lib/strftime.c
lib/strftime.h
lib/string.in.h
lib/strtoimax.c
lib/strtol.c
lib/strtoll.c
@ -848,6 +859,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/lstat.m4
m4/manywarnings.m4
m4/md5.m4
m4/memrchr.m4
m4/mktime.m4
m4/multiarch.m4
m4/nocrash.m4
@ -877,6 +889,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/stdio_h.m4
m4/stdlib_h.m4
m4/strftime.m4
m4/string_h.m4
m4/strtoimax.m4
m4/strtoll.m4
m4/strtoull.m4

23
m4/memrchr.m4 Normal file
View file

@ -0,0 +1,23 @@
# memrchr.m4 serial 10
dnl Copyright (C) 2002-2003, 2005-2007, 2009-2013 Free Software Foundation,
dnl Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_FUNC_MEMRCHR],
[
dnl Persuade glibc <string.h> to declare memrchr().
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
AC_CHECK_DECLS_ONCE([memrchr])
if test $ac_cv_have_decl_memrchr = no; then
HAVE_DECL_MEMRCHR=0
fi
AC_CHECK_FUNCS([memrchr])
])
# Prerequisites of lib/memrchr.c.
AC_DEFUN([gl_PREREQ_MEMRCHR], [:])

120
m4/string_h.m4 Normal file
View file

@ -0,0 +1,120 @@
# Configure a GNU-like replacement for <string.h>.
# Copyright (C) 2007-2013 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 21
# Written by Paul Eggert.
AC_DEFUN([gl_HEADER_STRING_H],
[
dnl Use AC_REQUIRE here, so that the default behavior below is expanded
dnl once only, before all statements that occur in other macros.
AC_REQUIRE([gl_HEADER_STRING_H_BODY])
])
AC_DEFUN([gl_HEADER_STRING_H_BODY],
[
AC_REQUIRE([AC_C_RESTRICT])
AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
gl_NEXT_HEADERS([string.h])
dnl Check for declarations of anything we want to poison if the
dnl corresponding gnulib module is not in use, and which is not
dnl guaranteed by C89.
gl_WARN_ON_USE_PREPARE([[#include <string.h>
]],
[ffsl ffsll memmem mempcpy memrchr rawmemchr stpcpy stpncpy strchrnul
strdup strncat strndup strnlen strpbrk strsep strcasestr strtok_r
strerror_r strsignal strverscmp])
])
AC_DEFUN([gl_STRING_MODULE_INDICATOR],
[
dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
gl_MODULE_INDICATOR_SET_VARIABLE([$1])
dnl Define it also as a C macro, for the benefit of the unit tests.
gl_MODULE_INDICATOR_FOR_TESTS([$1])
])
AC_DEFUN([gl_HEADER_STRING_H_DEFAULTS],
[
GNULIB_FFSL=0; AC_SUBST([GNULIB_FFSL])
GNULIB_FFSLL=0; AC_SUBST([GNULIB_FFSLL])
GNULIB_MEMCHR=0; AC_SUBST([GNULIB_MEMCHR])
GNULIB_MEMMEM=0; AC_SUBST([GNULIB_MEMMEM])
GNULIB_MEMPCPY=0; AC_SUBST([GNULIB_MEMPCPY])
GNULIB_MEMRCHR=0; AC_SUBST([GNULIB_MEMRCHR])
GNULIB_RAWMEMCHR=0; AC_SUBST([GNULIB_RAWMEMCHR])
GNULIB_STPCPY=0; AC_SUBST([GNULIB_STPCPY])
GNULIB_STPNCPY=0; AC_SUBST([GNULIB_STPNCPY])
GNULIB_STRCHRNUL=0; AC_SUBST([GNULIB_STRCHRNUL])
GNULIB_STRDUP=0; AC_SUBST([GNULIB_STRDUP])
GNULIB_STRNCAT=0; AC_SUBST([GNULIB_STRNCAT])
GNULIB_STRNDUP=0; AC_SUBST([GNULIB_STRNDUP])
GNULIB_STRNLEN=0; AC_SUBST([GNULIB_STRNLEN])
GNULIB_STRPBRK=0; AC_SUBST([GNULIB_STRPBRK])
GNULIB_STRSEP=0; AC_SUBST([GNULIB_STRSEP])
GNULIB_STRSTR=0; AC_SUBST([GNULIB_STRSTR])
GNULIB_STRCASESTR=0; AC_SUBST([GNULIB_STRCASESTR])
GNULIB_STRTOK_R=0; AC_SUBST([GNULIB_STRTOK_R])
GNULIB_MBSLEN=0; AC_SUBST([GNULIB_MBSLEN])
GNULIB_MBSNLEN=0; AC_SUBST([GNULIB_MBSNLEN])
GNULIB_MBSCHR=0; AC_SUBST([GNULIB_MBSCHR])
GNULIB_MBSRCHR=0; AC_SUBST([GNULIB_MBSRCHR])
GNULIB_MBSSTR=0; AC_SUBST([GNULIB_MBSSTR])
GNULIB_MBSCASECMP=0; AC_SUBST([GNULIB_MBSCASECMP])
GNULIB_MBSNCASECMP=0; AC_SUBST([GNULIB_MBSNCASECMP])
GNULIB_MBSPCASECMP=0; AC_SUBST([GNULIB_MBSPCASECMP])
GNULIB_MBSCASESTR=0; AC_SUBST([GNULIB_MBSCASESTR])
GNULIB_MBSCSPN=0; AC_SUBST([GNULIB_MBSCSPN])
GNULIB_MBSPBRK=0; AC_SUBST([GNULIB_MBSPBRK])
GNULIB_MBSSPN=0; AC_SUBST([GNULIB_MBSSPN])
GNULIB_MBSSEP=0; AC_SUBST([GNULIB_MBSSEP])
GNULIB_MBSTOK_R=0; AC_SUBST([GNULIB_MBSTOK_R])
GNULIB_STRERROR=0; AC_SUBST([GNULIB_STRERROR])
GNULIB_STRERROR_R=0; AC_SUBST([GNULIB_STRERROR_R])
GNULIB_STRSIGNAL=0; AC_SUBST([GNULIB_STRSIGNAL])
GNULIB_STRVERSCMP=0; AC_SUBST([GNULIB_STRVERSCMP])
HAVE_MBSLEN=0; AC_SUBST([HAVE_MBSLEN])
dnl Assume proper GNU behavior unless another module says otherwise.
HAVE_FFSL=1; AC_SUBST([HAVE_FFSL])
HAVE_FFSLL=1; AC_SUBST([HAVE_FFSLL])
HAVE_MEMCHR=1; AC_SUBST([HAVE_MEMCHR])
HAVE_DECL_MEMMEM=1; AC_SUBST([HAVE_DECL_MEMMEM])
HAVE_MEMPCPY=1; AC_SUBST([HAVE_MEMPCPY])
HAVE_DECL_MEMRCHR=1; AC_SUBST([HAVE_DECL_MEMRCHR])
HAVE_RAWMEMCHR=1; AC_SUBST([HAVE_RAWMEMCHR])
HAVE_STPCPY=1; AC_SUBST([HAVE_STPCPY])
HAVE_STPNCPY=1; AC_SUBST([HAVE_STPNCPY])
HAVE_STRCHRNUL=1; AC_SUBST([HAVE_STRCHRNUL])
HAVE_DECL_STRDUP=1; AC_SUBST([HAVE_DECL_STRDUP])
HAVE_DECL_STRNDUP=1; AC_SUBST([HAVE_DECL_STRNDUP])
HAVE_DECL_STRNLEN=1; AC_SUBST([HAVE_DECL_STRNLEN])
HAVE_STRPBRK=1; AC_SUBST([HAVE_STRPBRK])
HAVE_STRSEP=1; AC_SUBST([HAVE_STRSEP])
HAVE_STRCASESTR=1; AC_SUBST([HAVE_STRCASESTR])
HAVE_DECL_STRTOK_R=1; AC_SUBST([HAVE_DECL_STRTOK_R])
HAVE_DECL_STRERROR_R=1; AC_SUBST([HAVE_DECL_STRERROR_R])
HAVE_DECL_STRSIGNAL=1; AC_SUBST([HAVE_DECL_STRSIGNAL])
HAVE_STRVERSCMP=1; AC_SUBST([HAVE_STRVERSCMP])
REPLACE_MEMCHR=0; AC_SUBST([REPLACE_MEMCHR])
REPLACE_MEMMEM=0; AC_SUBST([REPLACE_MEMMEM])
REPLACE_STPNCPY=0; AC_SUBST([REPLACE_STPNCPY])
REPLACE_STRDUP=0; AC_SUBST([REPLACE_STRDUP])
REPLACE_STRSTR=0; AC_SUBST([REPLACE_STRSTR])
REPLACE_STRCASESTR=0; AC_SUBST([REPLACE_STRCASESTR])
REPLACE_STRCHRNUL=0; AC_SUBST([REPLACE_STRCHRNUL])
REPLACE_STRERROR=0; AC_SUBST([REPLACE_STRERROR])
REPLACE_STRERROR_R=0; AC_SUBST([REPLACE_STRERROR_R])
REPLACE_STRNCAT=0; AC_SUBST([REPLACE_STRNCAT])
REPLACE_STRNDUP=0; AC_SUBST([REPLACE_STRNDUP])
REPLACE_STRNLEN=0; AC_SUBST([REPLACE_STRNLEN])
REPLACE_STRSIGNAL=0; AC_SUBST([REPLACE_STRSIGNAL])
REPLACE_STRTOK_R=0; AC_SUBST([REPLACE_STRTOK_R])
UNDEFINE_STRTOK_R=0; AC_SUBST([UNDEFINE_STRTOK_R])
])

View file

@ -1,5 +1,14 @@
2013-02-11 Paul Eggert <eggert@cs.ucla.edu>
Tune by using memchr and memrchr.
* doc.c (Fsnarf_documentation):
* fileio.c (Fsubstitute_in_file_name):
* search.c (find_newline, scan_newline):
* xdisp.c (pos_visible_p, display_count_lines):
Use memchr and memrchr rather than scanning byte-by-byte.
* search.c (find_newline): Rename from scan_buffer.
Omit first arg TARGET, as it's always '\n'. All callers changed.
Clean up read_key_sequence a tiny bit more.
* keyboard.c (read_char_x_menu_prompt) [HAVE_MENUS]:
(read_key_sequence): Remove unused locals.

View file

@ -630,11 +630,10 @@ the same file name is found in the `doc-directory'. */)
break;
buf[filled] = 0;
p = buf;
end = buf + (filled < 512 ? filled : filled - 128);
while (p != end && *p != '\037') p++;
p = memchr (buf, '\037', end - buf);
/* p points to ^_Ffunctionname\n or ^_Vvarname\n or ^_Sfilename\n. */
if (p != end)
if (p)
{
end = strchr (p, '\n');

View file

@ -735,9 +735,8 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */)
/* This is the ONLY_IN_LINE case, check that NEW_POS and
FIELD_BOUND are on the same line by seeing whether
there's an intervening newline or not. */
|| (scan_buffer ('\n',
XFASTINT (new_pos), XFASTINT (field_bound),
fwd ? -1 : 1, &shortage, 1),
|| (find_newline (XFASTINT (new_pos), XFASTINT (field_bound),
fwd ? -1 : 1, &shortage, 1),
shortage != 0)))
/* Constrain NEW_POS to FIELD_BOUND. */
new_pos = field_bound;

View file

@ -1710,8 +1710,9 @@ those `/' is discarded. */)
else if (*p == '{')
{
o = ++p;
while (p != endp && *p != '}') p++;
if (*p != '}') goto missingclose;
p = memchr (p, '}', endp - p);
if (! p)
goto missingclose;
s = p;
}
else
@ -1779,8 +1780,9 @@ those `/' is discarded. */)
else if (*p == '{')
{
o = ++p;
while (p != endp && *p != '}') p++;
if (*p != '}') goto missingclose;
p = memchr (p, '}', endp - p);
if (! p)
goto missingclose;
s = p++;
}
else

View file

@ -3346,8 +3346,8 @@ extern ptrdiff_t fast_c_string_match_ignore_case (Lisp_Object, const char *,
extern ptrdiff_t fast_string_match_ignore_case (Lisp_Object, Lisp_Object);
extern ptrdiff_t fast_looking_at (Lisp_Object, ptrdiff_t, ptrdiff_t,
ptrdiff_t, ptrdiff_t, Lisp_Object);
extern ptrdiff_t scan_buffer (int, ptrdiff_t, ptrdiff_t, ptrdiff_t,
ptrdiff_t *, bool);
extern ptrdiff_t find_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t,
ptrdiff_t *, bool);
extern EMACS_INT scan_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
EMACS_INT, bool);
extern ptrdiff_t find_next_newline (ptrdiff_t, int);

View file

@ -40,7 +40,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
existing data structure, and disturb as little of the existing code
as possible.
So here's the tack. We add some caching to the scan_buffer
So here's the tack. We add some caching to the find_newline
function, so that when it searches for a newline, it notes that the
region between the start and end of the search contained no
newlines; then, the next time around, it consults this cache to see

View file

@ -619,7 +619,7 @@ newline_cache_on_off (struct buffer *buf)
}
/* Search for COUNT instances of the character TARGET between START and END.
/* Search for COUNT newlines between START and END.
If COUNT is positive, search forwards; END must be >= START.
If COUNT is negative, search backwards for the -COUNTth instance;
@ -634,14 +634,14 @@ newline_cache_on_off (struct buffer *buf)
this is not the same as the usual convention for Emacs motion commands.
If we don't find COUNT instances before reaching END, set *SHORTAGE
to the number of TARGETs left unfound, and return END.
to the number of newlines left unfound, and return END.
If ALLOW_QUIT, set immediate_quit. That's good to do
except when inside redisplay. */
ptrdiff_t
scan_buffer (int target, ptrdiff_t start, ptrdiff_t end,
ptrdiff_t count, ptrdiff_t *shortage, bool allow_quit)
find_newline (ptrdiff_t start, ptrdiff_t end,
ptrdiff_t count, ptrdiff_t *shortage, bool allow_quit)
{
struct region_cache *newline_cache;
ptrdiff_t end_byte = -1;
@ -656,7 +656,7 @@ scan_buffer (int target, ptrdiff_t start, ptrdiff_t end,
else
{
direction = -1;
if (!end)
if (!end)
end = BEGV, end_byte = BEGV_BYTE;
}
if (end_byte == -1)
@ -684,7 +684,7 @@ scan_buffer (int target, ptrdiff_t start, ptrdiff_t end,
/* If we're looking for a newline, consult the newline cache
to see where we can avoid some scanning. */
if (target == '\n' && newline_cache)
if (newline_cache)
{
ptrdiff_t next_change;
immediate_quit = 0;
@ -723,32 +723,32 @@ scan_buffer (int target, ptrdiff_t start, ptrdiff_t end,
while (cursor < ceiling_addr)
{
unsigned char *scan_start = cursor;
/* The dumb loop. */
while (*cursor != target && ++cursor < ceiling_addr)
;
unsigned char *nl = memchr (cursor, '\n', ceiling_addr - cursor);
/* If we're looking for newlines, cache the fact that
the region from start to cursor is free of them. */
if (target == '\n' && newline_cache)
know_region_cache (current_buffer, newline_cache,
BYTE_TO_CHAR (start_byte + scan_start - base),
BYTE_TO_CHAR (start_byte + cursor - base));
if (newline_cache)
{
unsigned char *low = cursor;
unsigned char *lim = nl ? nl : ceiling_addr;
know_region_cache (current_buffer, newline_cache,
BYTE_TO_CHAR (low - base + start_byte),
BYTE_TO_CHAR (lim - base + start_byte));
}
/* Did we find the target character? */
if (cursor < ceiling_addr)
{
if (--count == 0)
{
immediate_quit = 0;
return BYTE_TO_CHAR (start_byte + cursor - base + 1);
}
cursor++;
}
if (! nl)
break;
if (--count == 0)
{
immediate_quit = 0;
return BYTE_TO_CHAR (nl + 1 - base + start_byte);
}
cursor = nl + 1;
}
start = BYTE_TO_CHAR (start_byte + cursor - base);
start = BYTE_TO_CHAR (ceiling_addr - base + start_byte);
}
}
else
@ -760,7 +760,7 @@ scan_buffer (int target, ptrdiff_t start, ptrdiff_t end,
ptrdiff_t tem;
/* Consult the newline cache, if appropriate. */
if (target == '\n' && newline_cache)
if (newline_cache)
{
ptrdiff_t next_change;
immediate_quit = 0;
@ -794,31 +794,32 @@ scan_buffer (int target, ptrdiff_t start, ptrdiff_t end,
while (cursor >= ceiling_addr)
{
unsigned char *scan_start = cursor;
while (*cursor != target && --cursor >= ceiling_addr)
;
unsigned char *nl = memrchr (ceiling_addr, '\n',
cursor + 1 - ceiling_addr);
/* If we're looking for newlines, cache the fact that
the region from after the cursor to start is free of them. */
if (target == '\n' && newline_cache)
know_region_cache (current_buffer, newline_cache,
BYTE_TO_CHAR (start_byte + cursor - base),
BYTE_TO_CHAR (start_byte + scan_start - base));
if (newline_cache)
{
unsigned char *low = nl ? nl : ceiling_addr - 1;
unsigned char *lim = cursor;
know_region_cache (current_buffer, newline_cache,
BYTE_TO_CHAR (low - base + start_byte),
BYTE_TO_CHAR (lim - base + start_byte));
}
/* Did we find the target character? */
if (cursor >= ceiling_addr)
{
if (++count >= 0)
{
immediate_quit = 0;
return BYTE_TO_CHAR (start_byte + cursor - base);
}
cursor--;
}
if (! nl)
break;
if (++count >= 0)
{
immediate_quit = 0;
return BYTE_TO_CHAR (nl - base + start_byte);
}
cursor = nl - 1;
}
start = BYTE_TO_CHAR (start_byte + cursor - base);
start = BYTE_TO_CHAR (ceiling_addr - 1 - base + start_byte);
}
}
@ -828,8 +829,7 @@ scan_buffer (int target, ptrdiff_t start, ptrdiff_t end,
return start;
}
/* Search for COUNT instances of a line boundary, which means either a
newline or (if selective display enabled) a carriage return.
/* Search for COUNT instances of a line boundary.
Start at START. If COUNT is negative, search backwards.
We report the resulting position by calling TEMP_SET_PT_BOTH.
@ -860,9 +860,6 @@ scan_newline (ptrdiff_t start, ptrdiff_t start_byte,
bool old_immediate_quit = immediate_quit;
/* The code that follows is like scan_buffer
but checks for either newline or carriage return. */
if (allow_quit)
immediate_quit++;
@ -874,29 +871,25 @@ scan_newline (ptrdiff_t start, ptrdiff_t start_byte,
ceiling = min (limit_byte - 1, ceiling);
ceiling_addr = BYTE_POS_ADDR (ceiling) + 1;
base = (cursor = BYTE_POS_ADDR (start_byte));
while (1)
{
while (*cursor != '\n' && ++cursor != ceiling_addr)
;
if (cursor != ceiling_addr)
{
if (--count == 0)
{
immediate_quit = old_immediate_quit;
start_byte = start_byte + cursor - base + 1;
start = BYTE_TO_CHAR (start_byte);
TEMP_SET_PT_BOTH (start, start_byte);
return 0;
}
else
if (++cursor == ceiling_addr)
break;
}
else
do
{
unsigned char *nl = memchr (cursor, '\n', ceiling_addr - cursor);
if (! nl)
break;
if (--count == 0)
{
immediate_quit = old_immediate_quit;
start_byte += nl - base + 1;
start = BYTE_TO_CHAR (start_byte);
TEMP_SET_PT_BOTH (start, start_byte);
return 0;
}
cursor = nl + 1;
}
start_byte += cursor - base;
while (cursor < ceiling_addr);
start_byte += ceiling_addr - base;
}
}
else
@ -905,31 +898,28 @@ scan_newline (ptrdiff_t start, ptrdiff_t start_byte,
{
ceiling = BUFFER_FLOOR_OF (start_byte - 1);
ceiling = max (limit_byte, ceiling);
ceiling_addr = BYTE_POS_ADDR (ceiling) - 1;
ceiling_addr = BYTE_POS_ADDR (ceiling);
base = (cursor = BYTE_POS_ADDR (start_byte - 1) + 1);
while (1)
{
while (--cursor != ceiling_addr && *cursor != '\n')
;
if (cursor != ceiling_addr)
{
if (++count == 0)
{
immediate_quit = old_immediate_quit;
/* Return the position AFTER the match we found. */
start_byte = start_byte + cursor - base + 1;
start = BYTE_TO_CHAR (start_byte);
TEMP_SET_PT_BOTH (start, start_byte);
return 0;
}
}
else
unsigned char *nl = memrchr (ceiling_addr, '\n',
cursor - ceiling_addr);
if (! nl)
break;
if (++count == 0)
{
immediate_quit = old_immediate_quit;
/* Return the position AFTER the match we found. */
start_byte += nl - base + 1;
start = BYTE_TO_CHAR (start_byte);
TEMP_SET_PT_BOTH (start, start_byte);
return 0;
}
cursor = nl;
}
/* Here we add 1 to compensate for the last decrement
of CURSOR, which took it past the valid range. */
start_byte += cursor - base + 1;
start_byte += ceiling_addr - base;
}
}
@ -942,7 +932,7 @@ scan_newline (ptrdiff_t start, ptrdiff_t start_byte,
ptrdiff_t
find_next_newline_no_quit (ptrdiff_t from, ptrdiff_t cnt)
{
return scan_buffer ('\n', from, 0, cnt, (ptrdiff_t *) 0, 0);
return find_newline (from, 0, cnt, (ptrdiff_t *) 0, 0);
}
/* Like find_next_newline, but returns position before the newline,
@ -953,7 +943,7 @@ ptrdiff_t
find_before_next_newline (ptrdiff_t from, ptrdiff_t to, ptrdiff_t cnt)
{
ptrdiff_t shortage;
ptrdiff_t pos = scan_buffer ('\n', from, to, cnt, &shortage, 1);
ptrdiff_t pos = find_newline (from, to, cnt, &shortage, 1);
if (shortage == 0)
pos--;

View file

@ -1392,21 +1392,9 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
Lisp_Object cpos = make_number (charpos);
Lisp_Object spec = Fget_char_property (cpos, Qdisplay, Qnil);
Lisp_Object string = string_from_display_spec (spec);
int newline_in_string = 0;
if (STRINGP (string))
{
const char *s = SSDATA (string);
const char *e = s + SBYTES (string);
while (s < e)
{
if (*s++ == '\n')
{
newline_in_string = 1;
break;
}
}
}
bool newline_in_string
= (STRINGP (string)
&& memchr (SDATA (string), '\n', SBYTES (string)));
/* The tricky code below is needed because there's a
discrepancy between move_it_to and how we set cursor
when the display line ends in a newline from a
@ -14759,7 +14747,7 @@ compute_window_start_on_continuation_line (struct window *w)
SET_TEXT_POS (start_pos, ZV, ZV_BYTE);
/* Find the start of the continued line. This should be fast
because scan_buffer is fast (newline cache). */
because find_newline is fast (newline cache). */
row = w->desired_matrix->rows + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0);
init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos),
row, DEFAULT_FACE_ID);
@ -21626,31 +21614,36 @@ display_count_lines (ptrdiff_t start_byte,
ceiling = min (limit_byte - 1, ceiling);
ceiling_addr = BYTE_POS_ADDR (ceiling) + 1;
base = (cursor = BYTE_POS_ADDR (start_byte));
while (1)
do
{
if (selective_display)
while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
;
else
while (*cursor != '\n' && ++cursor != ceiling_addr)
;
if (cursor != ceiling_addr)
{
if (--count == 0)
{
start_byte += cursor - base + 1;
*byte_pos_ptr = start_byte;
return orig_count;
}
else
if (++cursor == ceiling_addr)
break;
while (*cursor != '\n' && *cursor != 015
&& ++cursor != ceiling_addr)
continue;
if (cursor == ceiling_addr)
break;
}
else
break;
{
cursor = memchr (cursor, '\n', ceiling_addr - cursor);
if (! cursor)
break;
}
cursor++;
if (--count == 0)
{
start_byte += cursor - base;
*byte_pos_ptr = start_byte;
return orig_count;
}
}
start_byte += cursor - base;
while (cursor < ceiling_addr);
start_byte += ceiling_addr - base;
}
}
else
@ -21659,35 +21652,35 @@ display_count_lines (ptrdiff_t start_byte,
{
ceiling = BUFFER_FLOOR_OF (start_byte - 1);
ceiling = max (limit_byte, ceiling);
ceiling_addr = BYTE_POS_ADDR (ceiling) - 1;
ceiling_addr = BYTE_POS_ADDR (ceiling);
base = (cursor = BYTE_POS_ADDR (start_byte - 1) + 1);
while (1)
{
if (selective_display)
while (--cursor != ceiling_addr
&& *cursor != '\n' && *cursor != 015)
;
else
while (--cursor != ceiling_addr && *cursor != '\n')
;
if (cursor != ceiling_addr)
{
if (++count == 0)
{
start_byte += cursor - base + 1;
*byte_pos_ptr = start_byte;
/* When scanning backwards, we should
not count the newline posterior to which we stop. */
return - orig_count - 1;
}
while (--cursor >= ceiling_addr
&& *cursor != '\n' && *cursor != 015)
continue;
if (cursor < ceiling_addr)
break;
}
else
break;
{
cursor = memrchr (ceiling_addr, '\n', cursor - ceiling_addr);
if (! cursor)
break;
}
if (++count == 0)
{
start_byte += cursor - base + 1;
*byte_pos_ptr = start_byte;
/* When scanning backwards, we should
not count the newline posterior to which we stop. */
return - orig_count - 1;
}
}
/* Here we add 1 to compensate for the last decrement
of CURSOR, which took it past the valid range. */
start_byte += cursor - base + 1;
start_byte += ceiling_addr - base;
}
}