glibc strlen:
https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=strin...
#include <libc-pointer-arith.h>
#include <string-fzb.h>
#include <string-fzc.h>
#include <string-fzi.h>
#include <string-shift.h>
#include <string.h>
#ifdef STRLEN
# define __strlen STRLEN
#endif
/* Return the length of the null-terminated string STR. Scan for
the null terminator quickly by testing four bytes at a time. */
size_t
__strlen (const char *str)
{
/* Align pointer to sizeof op_t. */
const uintptr_t s_int = (uintptr_t) str;
const op_t *word_ptr = (const op_t*) PTR_ALIGN_DOWN (str, sizeof (op_t));
op_t word = *word_ptr;
find_t mask = shift_find (find_zero_all (word), s_int);
if (mask != 0)
return index_first (mask);
do
word = *++word_ptr;
while (! has_zero (word));
return ((const char *) word_ptr) + index_first_zero (word) - str;
}
#ifndef STRLEN
weak_alias (__strlen, strlen)
libc_hidden_builtin_def (strlen)
#endif
NetBSD common strlen:
https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/common/...
size_t
strlen(const char *str)
{
const char *s;
for (s = str; *s; ++s)
continue;
return(s - str);
}
Apple strlen:
https://opensource.apple.com/source/Libc/Libc-1244.50.9/stri...
Apple strlen comes from FreeBSD. Until 2009, FreeBSD used an unoptimised strlen.
https://svnweb.FreeBSD.org/base/head/lib/libc/string/strlen....
size_t
strlen(str)
const char *str;
{
const char *s;
for (s = str; *s; ++s);
return(s - str);
}
FreeBSD eventually copied^1 NetBSD's x86_64 strlen.
1. "modeled after", "inspired by", etc.
https://svnweb.FreeBSD.org/base?view=revision&revision=18770...
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/limits.h>
#include <sys/types.h>
#include <string.h>
/*
* Portable strlen() for 32-bit and 64-bit systems.
*
* Rationale: it is generally much more efficient to do word length
* operations and avoid branches on modern computer systems, as
* compared to byte-length operations with a lot of branches.
*
* The expression:
*
* ((x - 0x01....01) & ~x & 0x80....80)
*
* would evaluate to a non-zero value iff any of the bytes in the
* original word is zero. However, we can further reduce ~1/3 of
* time if we consider that strlen() usually operate on 7-bit ASCII
* by employing the following expression, which allows false positive
* when high bit of 1 and use the tail case to catch these case:
*
* ((x - 0x01....01) & 0x80....80)
*
* This is more than 5.2 times as compared to the raw implementation
* on Intel T7300 under EM64T mode for strings longer than word length.
*/
/* Magic numbers for the algorithm */
#if LONG_BIT == 32
static const unsigned long mask01 = 0x01010101;
static const unsigned long mask80 = 0x80808080;
#elif LONG_BIT == 64
static const unsigned long mask01 = 0x0101010101010101;
static const unsigned long mask80 = 0x8080808080808080;
#else
#error Unsupported word size
#endif
#define LONGPTR_MASK (sizeof(long) - 1)
/*
* Helper macro to return string length if we caught the zero
* byte.
*/
#define testbyte(x) \
do { \
if (p[x] == '\0') \
return (p - str + x); \
} while (0)
size_t
strlen(const char *str)
{
const char *p;
const unsigned long *lp;
/* Skip the first few bytes until we have an aligned p */
for (p = str; (uintptr_t)p & LONGPTR_MASK; p++)
if (*p == '\0')
return (p - str);
/* Scan the rest of the string using word sized operation */
for (lp = (const unsigned long *)p; ; lp++)
if ((*lp - mask01) & mask80) {
p = (const char *)(lp);
testbyte(0);
testbyte(1);
testbyte(2);
testbyte(3);
#if (LONG_BIT >= 64)
testbyte(4);
testbyte(5);
testbyte(6);
testbyte(7);
#endif
}
/* NOTREACHED */
return 0;
}