mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-22 21:10:07 +00:00
5625f666ce
Currently strsep calls strpbrk is is now a veneer to strcspn. Calling strcspn directly is faster. Since it handles a delimiter string of size 1 as a special case, this is not needed in strsep itself. Although this means there is a slightly higher overhead if the delimiter size is 1, all other cases are slightly faster. The overall performance gain is 5-10% on AArch64. The string/bits/string2.h header contains optimizations for constant delimiters of size 1-3. Benchmarking these showed similar performance for size 1 (since in all cases strchr/strchrnul is used), while size 2 and 3 can give up to 2x speedup for small input strings. However if these cases are common it seems much better to add this optimization to strcspn. So move these header optimizations to string-inlines.c. Improve the strsep benchmark so that it actually benchmarks something. The current version contains a delimiter character at every position in the input string, so there is very little work to do, and the extremely inefficent simple_strsep implementation appears fastest in every case. The new version has either no match in the input for the fail case and a match halfway in the input for the success case. The input is then restored so that each iteration does exactly the same amount of work. Reduce the number of testcases since simple_strsep takes a lot of time now. * benchtests/bench-strsep.c (oldstrsep): Add old implementation. (do_one_test) Restore original string so iteration works. * string/string-inlines.c (do_test): Create better input strings. (test_main) Reduce number of testruns. * string/string-inlines.c (__old_strsep_1c): New function. (__old_strsep_2c): Likewise. (__old_strsep_3c): Likewise. * string/strsep.c (__strsep): Remove case of small delim string. Call strcspn directly rather than strpbrk. * string/bits/string2.h (__strsep): Remove define. (__strsep_1c): Remove. (__strsep_2c): Remove. (__strsep_3c): Remove. (strsep): Remove. * sysdeps/unix/sysv/linux/internal_statvfs.c (__statvfs_getflags): Rename to __strsep.
571 lines
14 KiB
C
571 lines
14 KiB
C
/* Copyright (C) 1999-2016 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/* <bits/string.h> and <bits/string2.h> declare some extern inline
|
|
functions. These functions are declared additionally here if
|
|
inlining is not possible. */
|
|
|
|
#undef __USE_STRING_INLINES
|
|
#define __USE_STRING_INLINES
|
|
#define _FORCE_INLINES
|
|
#define __STRING_INLINE /* empty */
|
|
#define __NO_INLINE__
|
|
|
|
#include <string.h>
|
|
#undef index
|
|
#undef rindex
|
|
|
|
#undef __NO_INLINE__
|
|
#include <bits/string.h>
|
|
#include <bits/string2.h>
|
|
|
|
#include "shlib-compat.h"
|
|
|
|
#if SHLIB_COMPAT (libc, GLIBC_2_1_1, GLIBC_2_25)
|
|
/* The inline functions are not used from GLIBC 2.25 and forward, however
|
|
they are required to provide the symbols through string-inlines.c
|
|
(if inlining is not possible for compatibility reasons). */
|
|
|
|
char *
|
|
__old_strtok_r_1c (char *__s, char __sep, char **__nextp)
|
|
{
|
|
char *__result;
|
|
if (__s == NULL)
|
|
__s = *__nextp;
|
|
while (*__s == __sep)
|
|
++__s;
|
|
__result = NULL;
|
|
if (*__s != '\0')
|
|
{
|
|
__result = __s++;
|
|
while (*__s != '\0')
|
|
if (*__s++ == __sep)
|
|
{
|
|
__s[-1] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
*__nextp = __s;
|
|
return __result;
|
|
}
|
|
compat_symbol (libc, __old_strtok_r_1c, __strtok_r_1c, GLIBC_2_1_1);
|
|
|
|
char *
|
|
__old_strsep_1c (char **__s, char __reject)
|
|
{
|
|
char *__retval = *__s;
|
|
if (__retval != NULL && (*__s = strchr (__retval, __reject)) != NULL)
|
|
*(*__s)++ = '\0';
|
|
return __retval;
|
|
}
|
|
compat_symbol (libc, __old_strsep_1c, __strsep_1c, GLIBC_2_1_1);
|
|
|
|
char *
|
|
__old_strsep_2c (char **__s, char __reject1, char __reject2)
|
|
{
|
|
char *__retval = *__s;
|
|
if (__retval != NULL)
|
|
{
|
|
char *__cp = __retval;
|
|
while (1)
|
|
{
|
|
if (*__cp == '\0')
|
|
{
|
|
__cp = NULL;
|
|
break;
|
|
}
|
|
if (*__cp == __reject1 || *__cp == __reject2)
|
|
{
|
|
*__cp++ = '\0';
|
|
break;
|
|
}
|
|
++__cp;
|
|
}
|
|
*__s = __cp;
|
|
}
|
|
return __retval;
|
|
}
|
|
compat_symbol (libc, __old_strsep_2c, __strsep_2c, GLIBC_2_1_1);
|
|
|
|
char *
|
|
__old_strsep_3c (char **__s, char __reject1, char __reject2, char __reject3)
|
|
{
|
|
char *__retval = *__s;
|
|
if (__retval != NULL)
|
|
{
|
|
char *__cp = __retval;
|
|
while (1)
|
|
{
|
|
if (*__cp == '\0')
|
|
{
|
|
__cp = NULL;
|
|
break;
|
|
}
|
|
if (*__cp == __reject1 || *__cp == __reject2 || *__cp == __reject3)
|
|
{
|
|
*__cp++ = '\0';
|
|
break;
|
|
}
|
|
++__cp;
|
|
}
|
|
*__s = __cp;
|
|
}
|
|
return __retval;
|
|
}
|
|
compat_symbol (libc, __old_strsep_3c, __strsep_3c, GLIBC_2_1_1);
|
|
#endif
|
|
|
|
#if SHLIB_COMPAT (libc, GLIBC_2_1_1, GLIBC_2_24)
|
|
/* The inline functions are not used from GLIBC 2.24 and forward, however
|
|
they are required to provide the symbols through string-inlines.c
|
|
(if inlining is not possible for compatibility reasons). */
|
|
size_t
|
|
__old_strcspn_c1 (const char *__s, int __reject)
|
|
{
|
|
size_t __result = 0;
|
|
while (__s[__result] != '\0' && __s[__result] != __reject)
|
|
++__result;
|
|
return __result;
|
|
}
|
|
compat_symbol (libc, __old_strcspn_c1, __strcspn_c1, GLIBC_2_1_1);
|
|
|
|
size_t
|
|
__old_strcspn_c2 (const char *__s, int __reject1, int __reject2)
|
|
{
|
|
size_t __result = 0;
|
|
while (__s[__result] != '\0' && __s[__result] != __reject1
|
|
&& __s[__result] != __reject2)
|
|
++__result;
|
|
return __result;
|
|
}
|
|
compat_symbol (libc, __old_strcspn_c2, __strcspn_c2, GLIBC_2_1_1);
|
|
|
|
size_t
|
|
__old_strcspn_c3 (const char *__s, int __reject1, int __reject2,
|
|
int __reject3)
|
|
{
|
|
size_t __result = 0;
|
|
while (__s[__result] != '\0' && __s[__result] != __reject1
|
|
&& __s[__result] != __reject2 && __s[__result] != __reject3)
|
|
++__result;
|
|
return __result;
|
|
}
|
|
compat_symbol (libc, __old_strcspn_c3, __strcspn_c3, GLIBC_2_1_1);
|
|
|
|
size_t
|
|
__old_strspn_c1 (const char *__s, int __accept)
|
|
{
|
|
size_t __result = 0;
|
|
/* Please note that __accept never can be '\0'. */
|
|
while (__s[__result] == __accept)
|
|
++__result;
|
|
return __result;
|
|
}
|
|
compat_symbol (libc, __old_strspn_c1, __strspn_c1, GLIBC_2_1_1);
|
|
|
|
size_t
|
|
__old_strspn_c2 (const char *__s, int __accept1, int __accept2)
|
|
{
|
|
size_t __result = 0;
|
|
/* Please note that __accept1 and __accept2 never can be '\0'. */
|
|
while (__s[__result] == __accept1 || __s[__result] == __accept2)
|
|
++__result;
|
|
return __result;
|
|
}
|
|
compat_symbol (libc, __old_strspn_c2, __strspn_c2, GLIBC_2_1_1);
|
|
|
|
size_t
|
|
__old_strspn_c3 (const char *__s, int __accept1, int __accept2,
|
|
int __accept3)
|
|
{
|
|
size_t __result = 0;
|
|
/* Please note that __accept1 to __accept3 never can be '\0'. */
|
|
while (__s[__result] == __accept1 || __s[__result] == __accept2
|
|
|| __s[__result] == __accept3)
|
|
++__result;
|
|
return __result;
|
|
}
|
|
compat_symbol (libc, __old_strspn_c3, __strspn_c3, GLIBC_2_1_1);
|
|
|
|
char *
|
|
__old_strpbrk_c2 (const char *__s, int __accept1, int __accept2)
|
|
{
|
|
/* Please note that __accept1 and __accept2 never can be '\0'. */
|
|
while (*__s != '\0' && *__s != __accept1 && *__s != __accept2)
|
|
++__s;
|
|
return *__s == '\0' ? NULL : (char *) (size_t) __s;
|
|
}
|
|
compat_symbol (libc, __old_strpbrk_c2, __strpbrk_c2, GLIBC_2_1_1);
|
|
|
|
char *
|
|
__old_strpbrk_c3 (const char *__s, int __accept1, int __accept2, int __accept3)
|
|
{
|
|
/* Please note that __accept1 to __accept3 never can be '\0'. */
|
|
while (*__s != '\0' && *__s != __accept1 && *__s != __accept2
|
|
&& *__s != __accept3)
|
|
++__s;
|
|
return *__s == '\0' ? NULL : (char *) (size_t) __s;
|
|
}
|
|
compat_symbol (libc, __old_strpbrk_c3, __strpbrk_c3, GLIBC_2_1_1);
|
|
|
|
/* These are a few types we need for the optimizations if we cannot
|
|
use unaligned memory accesses. */
|
|
# define __STRING2_COPY_TYPE(N) \
|
|
typedef struct { unsigned char __arr[N]; } \
|
|
__attribute__ ((__packed__)) __STRING2_COPY_ARR##N
|
|
__STRING2_COPY_TYPE (2);
|
|
__STRING2_COPY_TYPE (3);
|
|
__STRING2_COPY_TYPE (4);
|
|
__STRING2_COPY_TYPE (5);
|
|
__STRING2_COPY_TYPE (6);
|
|
__STRING2_COPY_TYPE (7);
|
|
__STRING2_COPY_TYPE (8);
|
|
# undef __STRING2_COPY_TYPE
|
|
|
|
|
|
# if _STRING_INLINE_unaligned
|
|
void *
|
|
__old_mempcpy_small (void *__dest1,
|
|
char __src0_1, char __src2_1, char __src4_1, char __src6_1,
|
|
__uint16_t __src0_2, __uint16_t __src4_2,
|
|
__uint32_t __src0_4, __uint32_t __src4_4,
|
|
size_t __srclen)
|
|
{
|
|
union {
|
|
__uint32_t __ui;
|
|
__uint16_t __usi;
|
|
unsigned char __uc;
|
|
unsigned char __c;
|
|
} *__u = __dest1;
|
|
switch ((unsigned int) __srclen)
|
|
{
|
|
case 1:
|
|
__u->__c = __src0_1;
|
|
__u = __extension__ ((void *) __u + 1);
|
|
break;
|
|
case 2:
|
|
__u->__usi = __src0_2;
|
|
__u = __extension__ ((void *) __u + 2);
|
|
break;
|
|
case 3:
|
|
__u->__usi = __src0_2;
|
|
__u = __extension__ ((void *) __u + 2);
|
|
__u->__c = __src2_1;
|
|
__u = __extension__ ((void *) __u + 1);
|
|
break;
|
|
case 4:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
break;
|
|
case 5:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__c = __src4_1;
|
|
__u = __extension__ ((void *) __u + 1);
|
|
break;
|
|
case 6:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__usi = __src4_2;
|
|
__u = __extension__ ((void *) __u + 2);
|
|
break;
|
|
case 7:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__usi = __src4_2;
|
|
__u = __extension__ ((void *) __u + 2);
|
|
__u->__c = __src6_1;
|
|
__u = __extension__ ((void *) __u + 1);
|
|
break;
|
|
case 8:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__ui = __src4_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
break;
|
|
}
|
|
return (void *) __u;
|
|
}
|
|
|
|
# else
|
|
|
|
void *
|
|
__old_mempcpy_small (void *__dest, char __src1,
|
|
__STRING2_COPY_ARR2 __src2, __STRING2_COPY_ARR3 __src3,
|
|
__STRING2_COPY_ARR4 __src4, __STRING2_COPY_ARR5 __src5,
|
|
__STRING2_COPY_ARR6 __src6, __STRING2_COPY_ARR7 __src7,
|
|
__STRING2_COPY_ARR8 __src8, size_t __srclen)
|
|
{
|
|
union {
|
|
char __c;
|
|
__STRING2_COPY_ARR2 __sca2;
|
|
__STRING2_COPY_ARR3 __sca3;
|
|
__STRING2_COPY_ARR4 __sca4;
|
|
__STRING2_COPY_ARR5 __sca5;
|
|
__STRING2_COPY_ARR6 __sca6;
|
|
__STRING2_COPY_ARR7 __sca7;
|
|
__STRING2_COPY_ARR8 __sca8;
|
|
} *__u = __dest;
|
|
switch ((unsigned int) __srclen)
|
|
{
|
|
case 1:
|
|
__u->__c = __src1;
|
|
break;
|
|
case 2:
|
|
__extension__ __u->__sca2 = __src2;
|
|
break;
|
|
case 3:
|
|
__extension__ __u->__sca3 = __src3;
|
|
break;
|
|
case 4:
|
|
__extension__ __u->__sca4 = __src4;
|
|
break;
|
|
case 5:
|
|
__extension__ __u->__sca5 = __src5;
|
|
break;
|
|
case 6:
|
|
__extension__ __u->__sca6 = __src6;
|
|
break;
|
|
case 7:
|
|
__extension__ __u->__sca7 = __src7;
|
|
break;
|
|
case 8:
|
|
__extension__ __u->__sca8 = __src8;
|
|
break;
|
|
}
|
|
return __extension__ ((void *) __u + __srclen);
|
|
}
|
|
# endif
|
|
compat_symbol (libc, __old_mempcpy_small, __mempcpy_small, GLIBC_2_1_1);
|
|
|
|
# if _STRING_INLINE_unaligned
|
|
char *
|
|
__old_strcpy_small (char *__dest,
|
|
__uint16_t __src0_2, __uint16_t __src4_2,
|
|
__uint32_t __src0_4, __uint32_t __src4_4,
|
|
size_t __srclen)
|
|
{
|
|
union {
|
|
__uint32_t __ui;
|
|
__uint16_t __usi;
|
|
unsigned char __uc;
|
|
} *__u = (void *) __dest;
|
|
switch ((unsigned int) __srclen)
|
|
{
|
|
case 1:
|
|
__u->__uc = '\0';
|
|
break;
|
|
case 2:
|
|
__u->__usi = __src0_2;
|
|
break;
|
|
case 3:
|
|
__u->__usi = __src0_2;
|
|
__u = __extension__ ((void *) __u + 2);
|
|
__u->__uc = '\0';
|
|
break;
|
|
case 4:
|
|
__u->__ui = __src0_4;
|
|
break;
|
|
case 5:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__uc = '\0';
|
|
break;
|
|
case 6:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__usi = __src4_2;
|
|
break;
|
|
case 7:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__usi = __src4_2;
|
|
__u = __extension__ ((void *) __u + 2);
|
|
__u->__uc = '\0';
|
|
break;
|
|
case 8:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__ui = __src4_4;
|
|
break;
|
|
}
|
|
return __dest;
|
|
}
|
|
|
|
# else
|
|
|
|
char *
|
|
__old_strcpy_small (char *__dest,
|
|
__STRING2_COPY_ARR2 __src2, __STRING2_COPY_ARR3 __src3,
|
|
__STRING2_COPY_ARR4 __src4, __STRING2_COPY_ARR5 __src5,
|
|
__STRING2_COPY_ARR6 __src6, __STRING2_COPY_ARR7 __src7,
|
|
__STRING2_COPY_ARR8 __src8, size_t __srclen)
|
|
{
|
|
union {
|
|
char __c;
|
|
__STRING2_COPY_ARR2 __sca2;
|
|
__STRING2_COPY_ARR3 __sca3;
|
|
__STRING2_COPY_ARR4 __sca4;
|
|
__STRING2_COPY_ARR5 __sca5;
|
|
__STRING2_COPY_ARR6 __sca6;
|
|
__STRING2_COPY_ARR7 __sca7;
|
|
__STRING2_COPY_ARR8 __sca8;
|
|
} *__u = (void *) __dest;
|
|
switch ((unsigned int) __srclen)
|
|
{
|
|
case 1:
|
|
__u->__c = '\0';
|
|
break;
|
|
case 2:
|
|
__extension__ __u->__sca2 = __src2;
|
|
break;
|
|
case 3:
|
|
__extension__ __u->__sca3 = __src3;
|
|
break;
|
|
case 4:
|
|
__extension__ __u->__sca4 = __src4;
|
|
break;
|
|
case 5:
|
|
__extension__ __u->__sca5 = __src5;
|
|
break;
|
|
case 6:
|
|
__extension__ __u->__sca6 = __src6;
|
|
break;
|
|
case 7:
|
|
__extension__ __u->__sca7 = __src7;
|
|
break;
|
|
case 8:
|
|
__extension__ __u->__sca8 = __src8;
|
|
break;
|
|
}
|
|
return __dest;
|
|
}
|
|
# endif
|
|
compat_symbol (libc, __old_strcpy_small, __strcpy_small, GLIBC_2_1_1);
|
|
|
|
# if _STRING_INLINE_unaligned
|
|
char *
|
|
__old_stpcpy_small (char *__dest,
|
|
__uint16_t __src0_2, __uint16_t __src4_2,
|
|
__uint32_t __src0_4, __uint32_t __src4_4,
|
|
size_t __srclen)
|
|
{
|
|
union {
|
|
unsigned int __ui;
|
|
unsigned short int __usi;
|
|
unsigned char __uc;
|
|
char __c;
|
|
} *__u = (void *) __dest;
|
|
switch ((unsigned int) __srclen)
|
|
{
|
|
case 1:
|
|
__u->__uc = '\0';
|
|
break;
|
|
case 2:
|
|
__u->__usi = __src0_2;
|
|
__u = __extension__ ((void *) __u + 1);
|
|
break;
|
|
case 3:
|
|
__u->__usi = __src0_2;
|
|
__u = __extension__ ((void *) __u + 2);
|
|
__u->__uc = '\0';
|
|
break;
|
|
case 4:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 3);
|
|
break;
|
|
case 5:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__uc = '\0';
|
|
break;
|
|
case 6:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__usi = __src4_2;
|
|
__u = __extension__ ((void *) __u + 1);
|
|
break;
|
|
case 7:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__usi = __src4_2;
|
|
__u = __extension__ ((void *) __u + 2);
|
|
__u->__uc = '\0';
|
|
break;
|
|
case 8:
|
|
__u->__ui = __src0_4;
|
|
__u = __extension__ ((void *) __u + 4);
|
|
__u->__ui = __src4_4;
|
|
__u = __extension__ ((void *) __u + 3);
|
|
break;
|
|
}
|
|
return &__u->__c;
|
|
}
|
|
|
|
# else
|
|
|
|
char *
|
|
__old_stpcpy_small (char *__dest,
|
|
__STRING2_COPY_ARR2 __src2, __STRING2_COPY_ARR3 __src3,
|
|
__STRING2_COPY_ARR4 __src4, __STRING2_COPY_ARR5 __src5,
|
|
__STRING2_COPY_ARR6 __src6, __STRING2_COPY_ARR7 __src7,
|
|
__STRING2_COPY_ARR8 __src8, size_t __srclen)
|
|
{
|
|
union {
|
|
char __c;
|
|
__STRING2_COPY_ARR2 __sca2;
|
|
__STRING2_COPY_ARR3 __sca3;
|
|
__STRING2_COPY_ARR4 __sca4;
|
|
__STRING2_COPY_ARR5 __sca5;
|
|
__STRING2_COPY_ARR6 __sca6;
|
|
__STRING2_COPY_ARR7 __sca7;
|
|
__STRING2_COPY_ARR8 __sca8;
|
|
} *__u = (void *) __dest;
|
|
switch ((unsigned int) __srclen)
|
|
{
|
|
case 1:
|
|
__u->__c = '\0';
|
|
break;
|
|
case 2:
|
|
__extension__ __u->__sca2 = __src2;
|
|
break;
|
|
case 3:
|
|
__extension__ __u->__sca3 = __src3;
|
|
break;
|
|
case 4:
|
|
__extension__ __u->__sca4 = __src4;
|
|
break;
|
|
case 5:
|
|
__extension__ __u->__sca5 = __src5;
|
|
break;
|
|
case 6:
|
|
__extension__ __u->__sca6 = __src6;
|
|
break;
|
|
case 7:
|
|
__extension__ __u->__sca7 = __src7;
|
|
break;
|
|
case 8:
|
|
__extension__ __u->__sca8 = __src8;
|
|
break;
|
|
}
|
|
return __dest + __srclen - 1;
|
|
}
|
|
# endif
|
|
compat_symbol (libc, __old_stpcpy_small, __stpcpy_small, GLIBC_2_1_1);
|
|
|
|
#endif
|